From b70500681cc069acdb7d3b6f10ec342d51523e88 Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Wed, 25 Mar 2026 17:20:31 -0400 Subject: [PATCH 1/3] feat!: bump minimum supported PHP version to 8.1 (#348) --- .github/workflows/ci.yml | 11 +---------- .github/workflows/lint.yml | 38 ++++++++++++++++++++++++++++++++++++++ .vscode/settings.json | 8 ++++++++ composer.json | 8 ++++---- 4 files changed, 51 insertions(+), 14 deletions(-) create mode 100644 .github/workflows/lint.yml create mode 100644 .vscode/settings.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e9011418..7cbf89cd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: true matrix: - php: ["7.3", "7.4", "8.1", "8.2", "8.3"] + php: ["8.1", "8.2", "8.3", "8.4", "8.5"] steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: shivammathur/setup-php@9e72090525849c5e82e596468b86eb55e9cc5401 # v2.32.0 @@ -37,15 +37,6 @@ jobs: run: | composer install --prefer-dist --no-progress --no-interaction - - name: Lint and formatting - if: >- - matrix.php == '7.4' || - matrix.php == '8.1' || - matrix.php == '8.2' || - matrix.php == '8.3' - run: | - composer run-script format-check - - name: Test run: | composer run-script test diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 00000000..7f9eea90 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,38 @@ +name: Lint + +on: + push: + branches: + - "main" + pull_request: {} + +defaults: + run: + shell: bash + +jobs: + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: shivammathur/setup-php@9e72090525849c5e82e596468b86eb55e9cc5401 # v2.32.0 + with: + php-version: "8.1" + tools: "composer" + + - name: Cache Composer packages + uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + with: + path: vendor + key: ${{ runner.os }}-php-8.1-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-php-8.1- + + - name: Install dependencies + run: | + composer install --prefer-dist --no-progress --no-interaction + + - name: Lint and formatting + run: | + composer run-script format-check diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..f77c6209 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "[github-actions-workflow]": { + "editor.defaultFormatter": "redhat.vscode-yaml" + }, + "[json]": { + "editor.defaultFormatter": "vscode.json-language-features" + } +} diff --git a/composer.json b/composer.json index a3a630a6..031644ff 100644 --- a/composer.json +++ b/composer.json @@ -10,13 +10,13 @@ } ], "require": { - "php": ">=7.3.0", + "php": ">=8.1.0", "ext-curl": "*", - "paragonie/halite": "^4.0" + "paragonie/halite": "^5.1" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.15|^3.6", - "phpunit/phpunit": "^9" + "friendsofphp/php-cs-fixer": "^3.0", + "phpunit/phpunit": "^10.5" }, "autoload": { "psr-4": { From ed3ad1986c42a0e6dad013b3f61d549ed8378555 Mon Sep 17 00:00:00 2001 From: "Garen J. Torikian" Date: Wed, 25 Mar 2026 17:25:57 -0400 Subject: [PATCH 2/3] make it 8.2 --- .github/workflows/ci.yml | 2 +- .github/workflows/lint.yml | 6 +++--- composer.json | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7cbf89cd..34c18e61 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: true matrix: - php: ["8.1", "8.2", "8.3", "8.4", "8.5"] + php: ["8.2", "8.3", "8.4", "8.5"] steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: shivammathur/setup-php@9e72090525849c5e82e596468b86eb55e9cc5401 # v2.32.0 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 7f9eea90..73423629 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -18,16 +18,16 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: shivammathur/setup-php@9e72090525849c5e82e596468b86eb55e9cc5401 # v2.32.0 with: - php-version: "8.1" + php-version: "8.2" tools: "composer" - name: Cache Composer packages uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 with: path: vendor - key: ${{ runner.os }}-php-8.1-${{ hashFiles('**/composer.lock') }} + key: ${{ runner.os }}-php-8.2-${{ hashFiles('**/composer.lock') }} restore-keys: | - ${{ runner.os }}-php-8.1- + ${{ runner.os }}-php-8.2- - name: Install dependencies run: | diff --git a/composer.json b/composer.json index 031644ff..195ae931 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,7 @@ } ], "require": { - "php": ">=8.1.0", + "php": ">=8.2.0", "ext-curl": "*", "paragonie/halite": "^5.1" }, From 8445d41bef9cb31056ade90e1a856110af2673b4 Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Thu, 9 Apr 2026 16:35:02 -0400 Subject: [PATCH 3/3] feat!: regenerate PHP SDK from the OpenAPI spec (#351) Co-authored-by: Claude Opus 4.6 (1M context) --- .php-cs-fixer.dist.php | 23 + composer.json | 18 +- docs/V5_MIGRATION_GUIDE.md | 812 +++++ lib/Actions.php | 128 + lib/AuditLogs.php | 224 -- lib/Client.php | 120 - lib/CookieSession.php | 149 - lib/DirectorySync.php | 248 -- lib/Exception/ApiException.php | 26 + lib/Exception/AuthenticationException.php | 9 +- lib/Exception/AuthorizationException.php | 9 +- lib/Exception/BadRequestException.php | 9 +- lib/Exception/BaseRequestException.php | 70 +- lib/Exception/ConfigurationException.php | 9 +- lib/Exception/ConflictException.php | 11 + lib/Exception/ConnectionException.php | 11 + lib/Exception/GenericException.php | 2 + lib/Exception/NotFoundException.php | 9 +- lib/Exception/RateLimitExceededException.php | 23 + lib/Exception/ServerException.php | 9 +- lib/Exception/TimeoutException.php | 11 + lib/Exception/UnexpectedValueException.php | 2 + .../UnprocessableEntityException.php | 11 + lib/Exception/WorkOSException.php | 2 + lib/HttpClient.php | 343 +++ lib/MFA.php | 222 -- lib/Organizations.php | 288 -- lib/PKCEHelper.php | 275 ++ lib/PaginatedResponse.php | 51 + lib/Passwordless.php | 100 +- lib/Portal.php | 55 - lib/RBAC.php | 496 ---- lib/RequestClient/CurlRequestClient.php | 128 - lib/RequestClient/RequestClientInterface.php | 23 - lib/RequestOptions.php | 19 + lib/Resource/ActionAuthenticationDenied.php | 50 + .../ActionAuthenticationDeniedContext.php | 59 + ...ActionAuthenticationDeniedContextActor.php | 41 + ...ionDeniedContextGoogleAnalyticsSession.php | 40 + .../ActionAuthenticationDeniedData.php | 65 + lib/Resource/ActionUserRegistrationDenied.php | 50 + .../ActionUserRegistrationDeniedContext.php | 59 + ...tionUserRegistrationDeniedContextActor.php | 41 + ...ionDeniedContextGoogleAnalyticsSession.php | 40 + .../ActionUserRegistrationDeniedData.php | 61 + lib/Resource/AddRolePermission.php | 32 + lib/Resource/ApiKey.php | 68 + lib/Resource/ApiKeyCreated.php | 50 + lib/Resource/ApiKeyCreatedContext.php | 59 + lib/Resource/ApiKeyCreatedContextActor.php | 41 + ...eyCreatedContextGoogleAnalyticsSession.php | 40 + lib/Resource/ApiKeyCreatedData.php | 68 + lib/Resource/ApiKeyCreatedDataOwner.php | 37 + lib/Resource/ApiKeyOwner.php | 37 + lib/Resource/ApiKeyRevoked.php | 50 + lib/Resource/ApiKeyRevokedContext.php | 59 + lib/Resource/ApiKeyRevokedContextActor.php | 41 + ...eyRevokedContextGoogleAnalyticsSession.php | 40 + lib/Resource/ApiKeyRevokedData.php | 68 + lib/Resource/ApiKeyRevokedDataOwner.php | 37 + lib/Resource/ApiKeyValidationResponse.php | 31 + lib/Resource/ApiKeyWithValue.php | 71 + lib/Resource/ApiKeyWithValueOwner.php | 37 + .../ApplicationCredentialsListItem.php | 52 + lib/Resource/ApplicationsOrder.php | 14 + lib/Resource/AssignRole.php | 44 + lib/Resource/AuditLogActionJson.php | 48 + lib/Resource/AuditLogConfiguration.php | 44 + .../AuditLogConfigurationLogStream.php | 49 + .../AuditLogConfigurationLogStreamState.php | 15 + .../AuditLogConfigurationLogStreamType.php | 17 + lib/Resource/AuditLogConfigurationState.php | 14 + lib/Resource/AuditLogCreateEventStatus.php | 19 - lib/Resource/AuditLogEvent.php | 62 + lib/Resource/AuditLogEventActor.php | 47 + lib/Resource/AuditLogEventContext.php | 36 + lib/Resource/AuditLogEventCreateResponse.php | 32 + lib/Resource/AuditLogEventIngestion.php | 36 + lib/Resource/AuditLogEventTarget.php | 47 + lib/Resource/AuditLogExport.php | 29 - lib/Resource/AuditLogExportCreation.php | 76 + lib/Resource/AuditLogExportJson.php | 52 + lib/Resource/AuditLogExportJsonState.php | 14 + lib/Resource/AuditLogSchema.php | 46 + lib/Resource/AuditLogSchemaActor.php | 35 + lib/Resource/AuditLogSchemaJson.php | 58 + lib/Resource/AuditLogSchemaJsonActor.php | 36 + lib/Resource/AuditLogSchemaJsonTarget.php | 39 + lib/Resource/AuditLogSchemaTarget.php | 39 + lib/Resource/AuditLogsOrder.php | 14 + lib/Resource/AuditLogsRetentionJson.php | 32 + lib/Resource/AuthenticateResponse.php | 60 + ...thenticateResponseAuthenticationMethod.php | 33 + .../AuthenticateResponseImpersonator.php | 37 + .../AuthenticateResponseOAuthToken.php | 52 + lib/Resource/AuthenticationChallenge.php | 56 + lib/Resource/AuthenticationChallengeSms.php | 29 - lib/Resource/AuthenticationChallengeTotp.php | 29 - .../AuthenticationChallengeVerifyResponse.php | 36 + .../AuthenticationChallengesVerifyRequest.php | 32 + .../AuthenticationEmailVerificationFailed.php | 50 + ...ticationEmailVerificationFailedContext.php | 59 + ...ionEmailVerificationFailedContextActor.php | 41 + ...ionFailedContextGoogleAnalyticsSession.php | 40 + ...henticationEmailVerificationFailedData.php | 55 + ...cationEmailVerificationFailedDataError.php | 37 + ...thenticationEmailVerificationSucceeded.php | 50 + ...ationEmailVerificationSucceededContext.php | 59 + ...EmailVerificationSucceededContextActor.php | 41 + ...SucceededContextGoogleAnalyticsSession.php | 40 + ...ticationEmailVerificationSucceededData.php | 51 + lib/Resource/AuthenticationFactor.php | 60 + .../AuthenticationFactorAndChallengeTotp.php | 31 - lib/Resource/AuthenticationFactorEnrolled.php | 60 + .../AuthenticationFactorEnrolledSms.php | 33 + .../AuthenticationFactorEnrolledTotp.php | 49 + .../AuthenticationFactorEnrolledType.php | 15 + lib/Resource/AuthenticationFactorSms.php | 46 +- lib/Resource/AuthenticationFactorTotp.php | 50 +- lib/Resource/AuthenticationFactorType.php | 15 + .../AuthenticationFactorsCreateRequest.php | 48 + ...AuthenticationFactorsCreateRequestType.php | 14 + lib/Resource/AuthenticationMFAFailed.php | 50 + .../AuthenticationMFAFailedContext.php | 59 + .../AuthenticationMFAFailedContextActor.php | 41 + ...MFAFailedContextGoogleAnalyticsSession.php | 40 + lib/Resource/AuthenticationMFAFailedData.php | 55 + .../AuthenticationMFAFailedDataError.php | 37 + lib/Resource/AuthenticationMFASucceeded.php | 50 + .../AuthenticationMFASucceededContext.php | 59 + ...AuthenticationMFASucceededContextActor.php | 41 + ...SucceededContextGoogleAnalyticsSession.php | 40 + .../AuthenticationMFASucceededData.php | 51 + .../AuthenticationMagicAuthFailed.php | 50 + .../AuthenticationMagicAuthFailedContext.php | 59 + ...henticationMagicAuthFailedContextActor.php | 41 + ...uthFailedContextGoogleAnalyticsSession.php | 40 + .../AuthenticationMagicAuthFailedData.php | 55 + ...AuthenticationMagicAuthFailedDataError.php | 37 + .../AuthenticationMagicAuthSucceeded.php | 50 + ...uthenticationMagicAuthSucceededContext.php | 59 + ...ticationMagicAuthSucceededContextActor.php | 41 + ...SucceededContextGoogleAnalyticsSession.php | 40 + .../AuthenticationMagicAuthSucceededData.php | 51 + lib/Resource/AuthenticationOAuthFailed.php | 50 + .../AuthenticationOAuthFailedContext.php | 59 + .../AuthenticationOAuthFailedContextActor.php | 41 + ...uthFailedContextGoogleAnalyticsSession.php | 40 + .../AuthenticationOAuthFailedData.php | 55 + .../AuthenticationOAuthFailedDataError.php | 37 + lib/Resource/AuthenticationOAuthSucceeded.php | 50 + .../AuthenticationOAuthSucceededContext.php | 59 + ...thenticationOAuthSucceededContextActor.php | 41 + ...SucceededContextGoogleAnalyticsSession.php | 40 + .../AuthenticationOAuthSucceededData.php | 51 + lib/Resource/AuthenticationPasskeyFailed.php | 50 + .../AuthenticationPasskeyFailedContext.php | 59 + ...uthenticationPasskeyFailedContextActor.php | 41 + ...keyFailedContextGoogleAnalyticsSession.php | 40 + .../AuthenticationPasskeyFailedData.php | 55 + .../AuthenticationPasskeyFailedDataError.php | 37 + .../AuthenticationPasskeySucceeded.php | 50 + .../AuthenticationPasskeySucceededContext.php | 59 + ...enticationPasskeySucceededContextActor.php | 41 + ...SucceededContextGoogleAnalyticsSession.php | 40 + .../AuthenticationPasskeySucceededData.php | 51 + lib/Resource/AuthenticationPasswordFailed.php | 50 + .../AuthenticationPasswordFailedContext.php | 59 + ...thenticationPasswordFailedContextActor.php | 41 + ...ordFailedContextGoogleAnalyticsSession.php | 40 + .../AuthenticationPasswordFailedData.php | 55 + .../AuthenticationPasswordFailedDataError.php | 37 + .../AuthenticationPasswordSucceeded.php | 50 + ...AuthenticationPasswordSucceededContext.php | 59 + ...nticationPasswordSucceededContextActor.php | 41 + ...SucceededContextGoogleAnalyticsSession.php | 40 + .../AuthenticationPasswordSucceededData.php | 51 + .../AuthenticationRadarRiskDetected.php | 50 + ...AuthenticationRadarRiskDetectedContext.php | 59 + ...nticationRadarRiskDetectedContextActor.php | 41 + ...kDetectedContextGoogleAnalyticsSession.php | 40 + .../AuthenticationRadarRiskDetectedData.php | 60 + ...henticationRadarRiskDetectedDataAction.php | 13 + lib/Resource/AuthenticationResponse.php | 51 - lib/Resource/AuthenticationSSOFailed.php | 50 + .../AuthenticationSSOFailedContext.php | 59 + .../AuthenticationSSOFailedContextActor.php | 41 + ...SSOFailedContextGoogleAnalyticsSession.php | 40 + lib/Resource/AuthenticationSSOFailedData.php | 59 + .../AuthenticationSSOFailedDataError.php | 37 + .../AuthenticationSSOFailedDataSSO.php | 41 + lib/Resource/AuthenticationSSOStarted.php | 50 + .../AuthenticationSSOStartedContext.php | 59 + .../AuthenticationSSOStartedContextActor.php | 41 + ...SOStartedContextGoogleAnalyticsSession.php | 40 + lib/Resource/AuthenticationSSOStartedData.php | 55 + .../AuthenticationSSOStartedDataSSO.php | 41 + lib/Resource/AuthenticationSSOSucceeded.php | 50 + .../AuthenticationSSOSucceededContext.php | 59 + ...AuthenticationSSOSucceededContextActor.php | 41 + ...SucceededContextGoogleAnalyticsSession.php | 40 + .../AuthenticationSSOSucceededData.php | 55 + .../AuthenticationSSOSucceededDataSSO.php | 41 + lib/Resource/AuthenticationSSOTimedOut.php | 50 + .../AuthenticationSSOTimedOutContext.php | 59 + .../AuthenticationSSOTimedOutContextActor.php | 41 + ...OTimedOutContextGoogleAnalyticsSession.php | 40 + .../AuthenticationSSOTimedOutData.php | 59 + .../AuthenticationSSOTimedOutDataError.php | 37 + .../AuthenticationSSOTimedOutDataSSO.php | 41 + lib/Resource/AuthorizationAssignment.php | 13 + lib/Resource/AuthorizationCheck.php | 32 + ...rizationCodeSessionAuthenticateRequest.php | 55 + lib/Resource/AuthorizationOrder.php | 14 + lib/Resource/AuthorizationPermission.php | 64 + lib/Resource/AuthorizationResource.php | 68 + .../AuthorizedConnectApplicationListData.php | 46 + lib/Resource/BaseWorkOSResource.php | 106 - lib/Resource/CORSOriginResponse.php | 48 + .../ChallengeAuthenticationFactor.php | 32 + lib/Resource/CheckAuthorization.php | 44 + lib/Resource/ConfirmEmailChange.php | 32 + lib/Resource/ConnectApplication.php | 63 + lib/Resource/ConnectedAccount.php | 68 + lib/Resource/ConnectedAccountState.php | 14 + lib/Resource/Connection.php | 111 +- lib/Resource/ConnectionActivated.php | 50 + lib/Resource/ConnectionActivatedContext.php | 59 + .../ConnectionActivatedContextActor.php | 41 + ...ActivatedContextGoogleAnalyticsSession.php | 40 + lib/Resource/ConnectionActivatedData.php | 76 + .../ConnectionActivatedDataDomain.php | 40 + lib/Resource/ConnectionDeactivated.php | 50 + lib/Resource/ConnectionDeactivatedContext.php | 59 + .../ConnectionDeactivatedContextActor.php | 41 + ...activatedContextGoogleAnalyticsSession.php | 40 + lib/Resource/ConnectionDeactivatedData.php | 76 + .../ConnectionDeactivatedDataDomain.php | 40 + lib/Resource/ConnectionDeleted.php | 50 + lib/Resource/ConnectionDeletedContext.php | 59 + .../ConnectionDeletedContextActor.php | 41 + ...onDeletedContextGoogleAnalyticsSession.php | 40 + lib/Resource/ConnectionDeletedData.php | 61 + .../ConnectionDeletedDataConnectionType.php | 61 + lib/Resource/ConnectionDeletedDataState.php | 16 + lib/Resource/ConnectionDomain.php | 40 + lib/Resource/ConnectionOption.php | 33 + ...nnectionSAMLCertificateRenewalRequired.php | 50 + ...nSAMLCertificateRenewalRequiredContext.php | 59 + ...CertificateRenewalRequiredContextActor.php | 41 + ...lRequiredContextGoogleAnalyticsSession.php | 40 + ...tionSAMLCertificateRenewalRequiredData.php | 41 + ...tificateRenewalRequiredDataCertificate.php | 41 + ...rtificateRenewalRequiredDataConnection.php | 37 + .../ConnectionSAMLCertificateRenewed.php | 50 + ...onnectionSAMLCertificateRenewedContext.php | 59 + ...tionSAMLCertificateRenewedContextActor.php | 41 + ...teRenewedContextGoogleAnalyticsSession.php | 40 + .../ConnectionSAMLCertificateRenewedData.php | 41 + ...nSAMLCertificateRenewedDataCertificate.php | 37 + ...eRenewedDataCertificateCertificateType.php | 14 + ...onSAMLCertificateRenewedDataConnection.php | 37 + lib/Resource/ConnectionState.php | 17 + lib/Resource/ConnectionStatus.php | 13 + lib/Resource/ConnectionType.php | 78 +- lib/Resource/ConnectionsConnectionType.php | 59 + lib/Resource/ConnectionsOrder.php | 14 + lib/Resource/CreateApplicationSecret.php | 28 + .../CreateAuthorizationPermission.php | 44 + lib/Resource/CreateAuthorizationResource.php | 60 + lib/Resource/CreateCORSOrigin.php | 32 + lib/Resource/CreateM2MApplication.php | 51 + lib/Resource/CreateMagicCodeAndReturn.php | 36 + lib/Resource/CreateOAuthApplication.php | 66 + lib/Resource/CreateOrganizationApiKey.php | 39 + lib/Resource/CreateOrganizationDomain.php | 36 + lib/Resource/CreateOrganizationRole.php | 44 + lib/Resource/CreatePasswordReset.php | 36 + lib/Resource/CreatePasswordResetToken.php | 32 + lib/Resource/CreateRedirectUri.php | 32 + lib/Resource/CreateRole.php | 44 + lib/Resource/CreateUser.php | 67 + lib/Resource/CreateUserInviteOptions.php | 52 + .../CreateUserInviteOptionsLocale.php | 101 + .../CreateUserOrganizationMembership.php | 47 + lib/Resource/CreateUserPasswordHashType.php | 17 + lib/Resource/CreateWebhookEndpoint.php | 39 + lib/Resource/CreateWebhookEndpointEvents.php | 80 + .../DataIntegrationAccessTokenResponse.php | 28 + .../DataIntegrationAuthorizeUrlResponse.php | 32 + ...sGetDataIntegrationAuthorizeUrlRequest.php | 40 + .../DataIntegrationsGetUserTokenRequest.php | 36 + lib/Resource/DataIntegrationsListResponse.php | 39 + .../DataIntegrationsListResponseData.php | 79 + ...ationsListResponseDataConnectedAccount.php | 75 + ...sListResponseDataConnectedAccountState.php | 14 + ...aIntegrationsListResponseDataOwnership.php | 13 + lib/Resource/DeviceAuthorizationResponse.php | 52 + .../DeviceCodeSessionAuthenticateRequest.php | 51 + lib/Resource/DirectoriesOrder.php | 14 + lib/Resource/Directory.php | 87 +- lib/Resource/DirectoryGroup.php | 76 +- lib/Resource/DirectoryGroupsOrder.php | 14 + lib/Resource/DirectoryMetadata.php | 37 + lib/Resource/DirectoryMetadataUser.php | 37 + lib/Resource/DirectoryState.php | 16 + lib/Resource/DirectoryType.php | 32 + lib/Resource/DirectoryUser.php | 189 +- lib/Resource/DirectoryUserEmail.php | 40 + lib/Resource/DirectoryUserState.php | 14 + lib/Resource/DirectoryUserWithGroups.php | 126 + lib/Resource/DirectoryUserWithGroupsEmail.php | 40 + lib/Resource/DirectoryUserWithGroupsState.php | 14 + lib/Resource/DirectoryUsersOrder.php | 14 + lib/Resource/Domain.php | 21 - lib/Resource/DsyncActivated.php | 50 + lib/Resource/DsyncActivatedContext.php | 59 + lib/Resource/DsyncActivatedContextActor.php | 41 + ...ActivatedContextGoogleAnalyticsSession.php | 40 + lib/Resource/DsyncActivatedData.php | 72 + lib/Resource/DsyncActivatedDataDomain.php | 40 + lib/Resource/DsyncDeactivated.php | 50 + lib/Resource/DsyncDeactivatedContext.php | 59 + lib/Resource/DsyncDeactivatedContextActor.php | 41 + ...activatedContextGoogleAnalyticsSession.php | 40 + lib/Resource/DsyncDeactivatedData.php | 72 + lib/Resource/DsyncDeactivatedDataDomain.php | 40 + lib/Resource/DsyncDeleted.php | 50 + lib/Resource/DsyncDeletedContext.php | 59 + lib/Resource/DsyncDeletedContextActor.php | 41 + ...ncDeletedContextGoogleAnalyticsSession.php | 40 + lib/Resource/DsyncDeletedData.php | 61 + lib/Resource/DsyncDeletedDataState.php | 16 + lib/Resource/DsyncDeletedDataType.php | 34 + lib/Resource/DsyncGroupCreated.php | 50 + lib/Resource/DsyncGroupCreatedContext.php | 59 + .../DsyncGroupCreatedContextActor.php | 41 + ...upCreatedContextGoogleAnalyticsSession.php | 40 + lib/Resource/DsyncGroupCreatedData.php | 68 + lib/Resource/DsyncGroupDeleted.php | 50 + lib/Resource/DsyncGroupDeletedContext.php | 59 + .../DsyncGroupDeletedContextActor.php | 41 + ...upDeletedContextGoogleAnalyticsSession.php | 40 + lib/Resource/DsyncGroupDeletedData.php | 68 + lib/Resource/DsyncGroupUpdated.php | 50 + lib/Resource/DsyncGroupUpdatedContext.php | 59 + .../DsyncGroupUpdatedContextActor.php | 41 + ...upUpdatedContextGoogleAnalyticsSession.php | 40 + lib/Resource/DsyncGroupUpdatedData.php | 72 + lib/Resource/DsyncGroupUserAdded.php | 50 + lib/Resource/DsyncGroupUserAddedContext.php | 59 + .../DsyncGroupUserAddedContextActor.php | 41 + ...UserAddedContextGoogleAnalyticsSession.php | 40 + lib/Resource/DsyncGroupUserAddedData.php | 41 + lib/Resource/DsyncGroupUserAddedDataGroup.php | 68 + lib/Resource/DsyncGroupUserAddedDataUser.php | 121 + .../DsyncGroupUserAddedDataUserEmail.php | 40 + .../DsyncGroupUserAddedDataUserRole.php | 33 + lib/Resource/DsyncGroupUserRemoved.php | 50 + lib/Resource/DsyncGroupUserRemovedContext.php | 59 + .../DsyncGroupUserRemovedContextActor.php | 41 + ...erRemovedContextGoogleAnalyticsSession.php | 40 + lib/Resource/DsyncGroupUserRemovedData.php | 41 + .../DsyncGroupUserRemovedDataGroup.php | 68 + .../DsyncGroupUserRemovedDataUser.php | 121 + .../DsyncGroupUserRemovedDataUserEmail.php | 40 + .../DsyncGroupUserRemovedDataUserRole.php | 33 + lib/Resource/DsyncUserCreated.php | 50 + lib/Resource/DsyncUserCreatedContext.php | 59 + lib/Resource/DsyncUserCreatedContextActor.php | 41 + ...erCreatedContextGoogleAnalyticsSession.php | 40 + lib/Resource/DsyncUserCreatedData.php | 121 + lib/Resource/DsyncUserCreatedDataEmail.php | 40 + lib/Resource/DsyncUserCreatedDataRole.php | 33 + lib/Resource/DsyncUserCreatedDataState.php | 14 + lib/Resource/DsyncUserDeleted.php | 50 + lib/Resource/DsyncUserDeletedContext.php | 59 + lib/Resource/DsyncUserDeletedContextActor.php | 41 + ...erDeletedContextGoogleAnalyticsSession.php | 40 + lib/Resource/DsyncUserDeletedData.php | 121 + lib/Resource/DsyncUserDeletedDataEmail.php | 40 + lib/Resource/DsyncUserDeletedDataRole.php | 33 + lib/Resource/DsyncUserUpdated.php | 50 + lib/Resource/DsyncUserUpdatedContext.php | 59 + lib/Resource/DsyncUserUpdatedContextActor.php | 41 + ...erUpdatedContextGoogleAnalyticsSession.php | 40 + lib/Resource/DsyncUserUpdatedData.php | 124 + lib/Resource/DsyncUserUpdatedDataEmail.php | 40 + lib/Resource/DsyncUserUpdatedDataRole.php | 33 + lib/Resource/EmailChange.php | 47 + lib/Resource/EmailChangeConfirmation.php | 36 + lib/Resource/EmailChangeConfirmationUser.php | 84 + lib/Resource/EmailVerification.php | 78 +- ...ficationCodeSessionAuthenticateRequest.php | 59 + lib/Resource/EmailVerificationCreated.php | 50 + .../EmailVerificationCreatedContext.php | 59 + .../EmailVerificationCreatedContextActor.php | 41 + ...onCreatedContextGoogleAnalyticsSession.php | 40 + lib/Resource/EmailVerificationCreatedData.php | 57 + .../EnrollUserAuthenticationFactor.php | 44 + lib/Resource/EventContext.php | 58 + lib/Resource/EventContextActor.php | 41 + lib/Resource/EventContextActorSource.php | 14 + .../EventContextGoogleAnalyticsSession.php | 40 + lib/Resource/EventListListMetadata.php | 33 + lib/Resource/EventSchema.php | 59 + lib/Resource/EventsOrder.php | 14 + lib/Resource/ExternalAuthCompleteResponse.php | 32 + lib/Resource/FeatureFlag.php | 96 +- lib/Resource/FeatureFlagOwner.php | 40 + lib/Resource/FeatureFlagsOrder.php | 14 + lib/Resource/Flag.php | 75 + lib/Resource/FlagCreated.php | 51 + lib/Resource/FlagCreatedContext.php | 37 + lib/Resource/FlagCreatedContextActor.php | 41 + .../FlagCreatedContextActorSource.php | 14 + lib/Resource/FlagCreatedData.php | 79 + lib/Resource/FlagCreatedDataOwner.php | 40 + lib/Resource/FlagDeleted.php | 51 + lib/Resource/FlagDeletedContext.php | 37 + lib/Resource/FlagDeletedContextActor.php | 41 + lib/Resource/FlagDeletedData.php | 79 + lib/Resource/FlagDeletedDataOwner.php | 40 + lib/Resource/FlagOwner.php | 40 + lib/Resource/FlagRuleUpdated.php | 51 + lib/Resource/FlagRuleUpdatedContext.php | 49 + .../FlagRuleUpdatedContextAccessType.php | 14 + lib/Resource/FlagRuleUpdatedContextActor.php | 40 + ...FlagRuleUpdatedContextConfiguredTarget.php | 43 + ...tedContextConfiguredTargetOrganization.php | 36 + ...RuleUpdatedContextConfiguredTargetUser.php | 36 + ...lagRuleUpdatedContextPreviousAttribute.php | 37 + ...UpdatedContextPreviousAttributeContext.php | 37 + ...eviousAttributeContextConfiguredTarget.php | 43 + ...uteContextConfiguredTargetOrganization.php | 36 + ...usAttributeContextConfiguredTargetUser.php | 36 + ...uleUpdatedContextPreviousAttributeData.php | 37 + lib/Resource/FlagRuleUpdatedData.php | 79 + lib/Resource/FlagRuleUpdatedDataOwner.php | 40 + lib/Resource/FlagUpdated.php | 51 + lib/Resource/FlagUpdatedContext.php | 41 + lib/Resource/FlagUpdatedContextActor.php | 41 + .../FlagUpdatedContextPreviousAttribute.php | 33 + ...lagUpdatedContextPreviousAttributeData.php | 52 + lib/Resource/FlagUpdatedData.php | 79 + lib/Resource/FlagUpdatedDataOwner.php | 40 + lib/Resource/GenerateLink.php | 65 + lib/Resource/GenerateLinkIntent.php | 18 + lib/Resource/Impersonator.php | 24 - lib/Resource/IntentOptions.php | 32 + lib/Resource/Invitation.php | 112 +- lib/Resource/InvitationAccepted.php | 50 + lib/Resource/InvitationAcceptedContext.php | 59 + .../InvitationAcceptedContextActor.php | 41 + ...nAcceptedContextGoogleAnalyticsSession.php | 40 + lib/Resource/InvitationAcceptedData.php | 77 + lib/Resource/InvitationCreated.php | 50 + lib/Resource/InvitationCreatedContext.php | 59 + .../InvitationCreatedContextActor.php | 41 + ...onCreatedContextGoogleAnalyticsSession.php | 40 + lib/Resource/InvitationCreatedData.php | 77 + lib/Resource/InvitationResent.php | 50 + lib/Resource/InvitationResentContext.php | 59 + lib/Resource/InvitationResentContextActor.php | 41 + ...ionResentContextGoogleAnalyticsSession.php | 40 + lib/Resource/InvitationResentData.php | 77 + lib/Resource/InvitationRevoked.php | 50 + lib/Resource/InvitationRevokedContext.php | 59 + .../InvitationRevokedContextActor.php | 41 + ...onRevokedContextGoogleAnalyticsSession.php | 40 + lib/Resource/InvitationRevokedData.php | 77 + lib/Resource/InvitationState.php | 15 + lib/Resource/JWTTemplateResponse.php | 44 + lib/Resource/JsonSerializableTrait.php | 15 + lib/Resource/JwksResponse.php | 35 + lib/Resource/JwksResponseKeys.php | 63 + lib/Resource/ListData.php | 71 + lib/Resource/ListDataType.php | 13 + lib/Resource/ListModel.php | 38 + .../MFATotpSessionAuthenticateRequest.php | 63 + lib/Resource/MagicAuth.php | 78 +- ...agicAuthCodeSessionAuthenticateRequest.php | 63 + lib/Resource/MagicAuthCreated.php | 50 + lib/Resource/MagicAuthCreatedContext.php | 59 + lib/Resource/MagicAuthCreatedContextActor.php | 41 + ...thCreatedContextGoogleAnalyticsSession.php | 40 + lib/Resource/MagicAuthCreatedData.php | 57 + lib/Resource/NewConnectApplicationSecret.php | 56 + lib/Resource/OAuthTokens.php | 40 - lib/Resource/Order.php | 14 - lib/Resource/Organization.php | 91 +- lib/Resource/OrganizationCreated.php | 50 + lib/Resource/OrganizationCreatedContext.php | 59 + .../OrganizationCreatedContextActor.php | 41 + ...onCreatedContextGoogleAnalyticsSession.php | 40 + lib/Resource/OrganizationCreatedData.php | 71 + .../OrganizationCreatedDataDomain.php | 68 + lib/Resource/OrganizationDeleted.php | 50 + lib/Resource/OrganizationDeletedContext.php | 59 + .../OrganizationDeletedContextActor.php | 41 + ...onDeletedContextGoogleAnalyticsSession.php | 40 + lib/Resource/OrganizationDeletedData.php | 71 + .../OrganizationDeletedDataDomain.php | 68 + lib/Resource/OrganizationDomain.php | 68 + lib/Resource/OrganizationDomainCreated.php | 50 + .../OrganizationDomainCreatedContext.php | 59 + .../OrganizationDomainCreatedContextActor.php | 41 + ...inCreatedContextGoogleAnalyticsSession.php | 40 + .../OrganizationDomainCreatedData.php | 69 + lib/Resource/OrganizationDomainData.php | 36 + lib/Resource/OrganizationDomainDataState.php | 13 + lib/Resource/OrganizationDomainDeleted.php | 50 + .../OrganizationDomainDeletedContext.php | 59 + .../OrganizationDomainDeletedContextActor.php | 41 + ...inDeletedContextGoogleAnalyticsSession.php | 40 + .../OrganizationDomainDeletedData.php | 69 + lib/Resource/OrganizationDomainStandAlone.php | 68 + .../OrganizationDomainStandAloneState.php | 16 + ...onDomainStandAloneVerificationStrategy.php | 13 + lib/Resource/OrganizationDomainState.php | 16 + lib/Resource/OrganizationDomainUpdated.php | 50 + .../OrganizationDomainUpdatedContext.php | 59 + .../OrganizationDomainUpdatedContextActor.php | 41 + ...inUpdatedContextGoogleAnalyticsSession.php | 40 + .../OrganizationDomainUpdatedData.php | 69 + .../OrganizationDomainVerificationFailed.php | 50 + ...izationDomainVerificationFailedContext.php | 59 + ...onDomainVerificationFailedContextActor.php | 41 + ...ionFailedContextGoogleAnalyticsSession.php | 40 + ...ganizationDomainVerificationFailedData.php | 37 + ...rificationFailedDataOrganizationDomain.php | 69 + ...tionDomainVerificationFailedDataReason.php | 13 + ...OrganizationDomainVerificationStrategy.php | 13 + lib/Resource/OrganizationDomainVerified.php | 50 + .../OrganizationDomainVerifiedContext.php | 59 + ...OrganizationDomainVerifiedContextActor.php | 41 + ...nVerifiedContextGoogleAnalyticsSession.php | 40 + .../OrganizationDomainVerifiedData.php | 69 + lib/Resource/OrganizationInput.php | 61 + lib/Resource/OrganizationMembership.php | 125 +- .../OrganizationMembershipCreated.php | 50 + .../OrganizationMembershipCreatedContext.php | 59 + ...anizationMembershipCreatedContextActor.php | 41 + ...ipCreatedContextGoogleAnalyticsSession.php | 40 + .../OrganizationMembershipCreatedData.php | 79 + .../OrganizationMembershipDeleted.php | 50 + .../OrganizationMembershipDeletedContext.php | 59 + ...anizationMembershipDeletedContextActor.php | 41 + ...ipDeletedContextGoogleAnalyticsSession.php | 40 + .../OrganizationMembershipDeletedData.php | 79 + lib/Resource/OrganizationMembershipStatus.php | 14 + .../OrganizationMembershipUpdated.php | 50 + .../OrganizationMembershipUpdatedContext.php | 59 + ...anizationMembershipUpdatedContextActor.php | 41 + ...ipUpdatedContextGoogleAnalyticsSession.php | 40 + .../OrganizationMembershipUpdatedData.php | 79 + lib/Resource/OrganizationRoleCreated.php | 50 + .../OrganizationRoleCreatedContext.php | 59 + .../OrganizationRoleCreatedContextActor.php | 41 + ...leCreatedContextGoogleAnalyticsSession.php | 40 + lib/Resource/OrganizationRoleCreatedData.php | 68 + lib/Resource/OrganizationRoleDeleted.php | 50 + .../OrganizationRoleDeletedContext.php | 59 + .../OrganizationRoleDeletedContextActor.php | 41 + ...leDeletedContextGoogleAnalyticsSession.php | 40 + lib/Resource/OrganizationRoleDeletedData.php | 68 + lib/Resource/OrganizationRoleUpdated.php | 50 + .../OrganizationRoleUpdatedContext.php | 59 + .../OrganizationRoleUpdatedContextActor.php | 41 + ...leUpdatedContextGoogleAnalyticsSession.php | 40 + lib/Resource/OrganizationRoleUpdatedData.php | 68 + ...ionSelectionSessionAuthenticateRequest.php | 59 + lib/Resource/OrganizationUpdated.php | 50 + lib/Resource/OrganizationUpdatedContext.php | 59 + .../OrganizationUpdatedContextActor.php | 41 + ...onUpdatedContextGoogleAnalyticsSession.php | 40 + lib/Resource/OrganizationUpdatedData.php | 71 + .../OrganizationUpdatedDataDomain.php | 68 + lib/Resource/OrganizationsApiKeysOrder.php | 14 + .../OrganizationsFeatureFlagsOrder.php | 14 + lib/Resource/OrganizationsOrder.php | 14 + lib/Resource/PaginatedResource.php | 224 -- lib/Resource/PasswordReset.php | 78 +- lib/Resource/PasswordResetCreated.php | 50 + lib/Resource/PasswordResetCreatedContext.php | 59 + .../PasswordResetCreatedContextActor.php | 41 + ...etCreatedContextGoogleAnalyticsSession.php | 40 + lib/Resource/PasswordResetCreatedData.php | 53 + lib/Resource/PasswordResetSucceeded.php | 50 + .../PasswordResetSucceededContext.php | 59 + .../PasswordResetSucceededContextActor.php | 41 + ...SucceededContextGoogleAnalyticsSession.php | 40 + lib/Resource/PasswordResetSucceededData.php | 53 + .../PasswordSessionAuthenticateRequest.php | 63 + lib/Resource/PasswordlessSession.php | 27 - lib/Resource/Permission.php | 91 +- lib/Resource/PermissionCreated.php | 50 + lib/Resource/PermissionCreatedContext.php | 59 + .../PermissionCreatedContextActor.php | 41 + ...onCreatedContextGoogleAnalyticsSession.php | 40 + lib/Resource/PermissionCreatedData.php | 61 + lib/Resource/PermissionDeleted.php | 50 + lib/Resource/PermissionDeletedContext.php | 59 + .../PermissionDeletedContextActor.php | 41 + ...onDeletedContextGoogleAnalyticsSession.php | 40 + lib/Resource/PermissionDeletedData.php | 61 + lib/Resource/PermissionUpdated.php | 50 + lib/Resource/PermissionUpdatedContext.php | 59 + .../PermissionUpdatedContextActor.php | 41 + ...onUpdatedContextGoogleAnalyticsSession.php | 40 + lib/Resource/PermissionUpdatedData.php | 61 + lib/Resource/PermissionsOrder.php | 14 + lib/Resource/PortalLink.php | 19 - lib/Resource/PortalLinkResponse.php | 32 + lib/Resource/Profile.php | 151 +- lib/Resource/ProfileAndToken.php | 30 - lib/Resource/ProfileConnectionType.php | 62 + lib/Resource/RadarAction.php | 13 + .../RadarListEntryAlreadyPresentResponse.php | 32 + lib/Resource/RadarStandaloneAssessRequest.php | 56 + .../RadarStandaloneAssessRequestAction.php | 19 + ...RadarStandaloneAssessRequestAuthMethod.php | 19 + ...rStandaloneDeleteRadarListEntryRequest.php | 32 + lib/Resource/RadarStandaloneResponse.php | 48 + .../RadarStandaloneResponseBlocklistType.php | 18 + .../RadarStandaloneResponseControl.php | 21 + .../RadarStandaloneResponseVerdict.php | 14 + ...darStandaloneUpdateRadarAttemptRequest.php | 36 + .../RadarStandaloneUpdateRadarListRequest.php | 32 + lib/Resource/RadarType.php | 18 + lib/Resource/RedirectUri.php | 52 + lib/Resource/RedirectUriInput.php | 36 + ...RefreshTokenSessionAuthenticateRequest.php | 59 + lib/Resource/RemoveRole.php | 44 + lib/Resource/ResendUserInviteOptions.php | 32 + .../ResendUserInviteOptionsLocale.php | 101 + lib/Resource/ResetPasswordResponse.php | 32 + lib/Resource/Response.php | 47 - lib/Resource/RevokeSession.php | 36 + lib/Resource/Role.php | 101 +- lib/Resource/RoleAssignment.php | 52 + lib/Resource/RoleAssignmentResource.php | 41 + lib/Resource/RoleCreated.php | 50 + lib/Resource/RoleCreatedContext.php | 59 + lib/Resource/RoleCreatedContextActor.php | 41 + ...leCreatedContextGoogleAnalyticsSession.php | 40 + lib/Resource/RoleCreatedData.php | 56 + lib/Resource/RoleDeleted.php | 50 + lib/Resource/RoleDeletedContext.php | 59 + lib/Resource/RoleDeletedContextActor.php | 41 + ...leDeletedContextGoogleAnalyticsSession.php | 40 + lib/Resource/RoleDeletedData.php | 56 + lib/Resource/RoleList.php | 38 + lib/Resource/RoleResponse.php | 18 - lib/Resource/RoleType.php | 13 + lib/Resource/RoleUpdated.php | 50 + lib/Resource/RoleUpdatedContext.php | 59 + lib/Resource/RoleUpdatedContextActor.php | 41 + ...leUpdatedContextGoogleAnalyticsSession.php | 40 + lib/Resource/RoleUpdatedData.php | 56 + lib/Resource/SSOAuthorizeUrlResponse.php | 32 + .../SSODeviceAuthorizationRequest.php | 32 + lib/Resource/SSOIntentOptions.php | 36 + lib/Resource/SSOLogoutAuthorizeRequest.php | 32 + lib/Resource/SSOLogoutAuthorizeResponse.php | 36 + lib/Resource/SSOProvider.php | 15 + lib/Resource/SSOTokenResponse.php | 48 + lib/Resource/SSOTokenResponseOAuthToken.php | 52 + lib/Resource/SendEmailChange.php | 32 + .../SendVerificationEmailResponse.php | 32 + lib/Resource/Session.php | 54 - .../SessionAuthenticationFailureResponse.php | 43 - .../SessionAuthenticationSuccessResponse.php | 102 - lib/Resource/SessionCreated.php | 50 + lib/Resource/SessionCreatedContext.php | 59 + lib/Resource/SessionCreatedContextActor.php | 41 + ...onCreatedContextGoogleAnalyticsSession.php | 40 + lib/Resource/SessionCreatedData.php | 81 + .../SessionCreatedDataImpersonator.php | 37 + lib/Resource/SessionRevoked.php | 50 + lib/Resource/SessionRevokedContext.php | 59 + lib/Resource/SessionRevokedContextActor.php | 41 + ...onRevokedContextGoogleAnalyticsSession.php | 40 + lib/Resource/SessionRevokedData.php | 81 + .../SessionRevokedDataImpersonator.php | 37 + lib/Resource/SetRolePermissions.php | 35 + lib/Resource/SlimRole.php | 33 + lib/Resource/TokenQuery.php | 44 + lib/Resource/UpdateAuditLogsRetention.php | 32 + .../UpdateAuthorizationPermission.php | 36 + lib/Resource/UpdateAuthorizationResource.php | 48 + lib/Resource/UpdateJWTTemplate.php | 32 + lib/Resource/UpdateOAuthApplication.php | 50 + lib/Resource/UpdateOrganization.php | 66 + lib/Resource/UpdateOrganizationRole.php | 36 + lib/Resource/UpdateRole.php | 36 + lib/Resource/UpdateUser.php | 71 + .../UpdateUserOrganizationMembership.php | 39 + lib/Resource/UpdateUserPasswordHashType.php | 17 + lib/Resource/UpdateWebhookEndpoint.php | 43 + lib/Resource/UpdateWebhookEndpointEvents.php | 80 + lib/Resource/UpdateWebhookEndpointStatus.php | 13 + lib/Resource/User.php | 109 +- lib/Resource/UserAndToken.php | 30 - ...UserAuthenticationFactorEnrollResponse.php | 36 + lib/Resource/UserAuthenticationFactorTotp.php | 31 - lib/Resource/UserConsentOption.php | 47 + lib/Resource/UserConsentOptionChoice.php | 36 + lib/Resource/UserCreated.php | 50 + lib/Resource/UserCreatedContext.php | 59 + lib/Resource/UserCreatedContextActor.php | 41 + ...erCreatedContextGoogleAnalyticsSession.php | 40 + lib/Resource/UserCreatedData.php | 84 + lib/Resource/UserDeleted.php | 50 + lib/Resource/UserDeletedContext.php | 59 + lib/Resource/UserDeletedContextActor.php | 41 + ...erDeletedContextGoogleAnalyticsSession.php | 40 + lib/Resource/UserDeletedData.php | 84 + lib/Resource/UserIdentitiesGetItem.php | 40 + .../UserIdentitiesGetItemProvider.php | 25 + lib/Resource/UserInvite.php | 84 + lib/Resource/UserInviteState.php | 15 + .../UserManagementAuthenticationProvider.php | 16 + ...UserManagementAuthenticationScreenHint.php | 13 + .../UserManagementInvitationsOrder.php | 14 + lib/Resource/UserManagementLoginRequest.php | 43 + ...nagementMultiFactorAuthenticationOrder.php | 14 + ...rManagementOrganizationMembershipOrder.php | 14 + ...nagementOrganizationMembershipStatuses.php | 14 + ...gementUsersAuthorizedApplicationsOrder.php | 14 + .../UserManagementUsersFeatureFlagsOrder.php | 14 + lib/Resource/UserManagementUsersOrder.php | 14 + lib/Resource/UserObject.php | 51 + lib/Resource/UserOrganizationMembership.php | 75 + ...UserOrganizationMembershipBaseListData.php | 71 + ...ganizationMembershipBaseListDataStatus.php | 14 + .../UserOrganizationMembershipStatus.php | 14 + lib/Resource/UserResponse.php | 26 - lib/Resource/UserSessionsAuthMethod.php | 21 + lib/Resource/UserSessionsImpersonator.php | 37 + lib/Resource/UserSessionsListItem.php | 80 + lib/Resource/UserSessionsStatus.php | 14 + lib/Resource/UserUpdated.php | 50 + lib/Resource/UserUpdatedContext.php | 59 + lib/Resource/UserUpdatedContextActor.php | 41 + ...erUpdatedContextGoogleAnalyticsSession.php | 40 + lib/Resource/UserUpdatedData.php | 84 + lib/Resource/ValidateApiKey.php | 32 + .../VaultByokKeyVerificationCompleted.php | 50 + ...ultByokKeyVerificationCompletedContext.php | 59 + ...okKeyVerificationCompletedContextActor.php | 41 + ...CompletedContextGoogleAnalyticsSession.php | 40 + .../VaultByokKeyVerificationCompletedData.php | 41 + ...eyVerificationCompletedDataKeyProvider.php | 14 + lib/Resource/VaultDataCreated.php | 50 + lib/Resource/VaultDataCreatedContext.php | 59 + lib/Resource/VaultDataCreatedContextActor.php | 41 + ...taCreatedContextGoogleAnalyticsSession.php | 40 + lib/Resource/VaultDataCreatedData.php | 52 + lib/Resource/VaultDataDeleted.php | 50 + lib/Resource/VaultDataDeletedContext.php | 59 + lib/Resource/VaultDataDeletedContextActor.php | 41 + ...taDeletedContextGoogleAnalyticsSession.php | 40 + lib/Resource/VaultDataDeletedData.php | 44 + lib/Resource/VaultDataRead.php | 50 + lib/Resource/VaultDataReadContext.php | 59 + lib/Resource/VaultDataReadContextActor.php | 41 + ...tDataReadContextGoogleAnalyticsSession.php | 40 + lib/Resource/VaultDataReadData.php | 48 + lib/Resource/VaultDataUpdated.php | 50 + lib/Resource/VaultDataUpdatedContext.php | 59 + lib/Resource/VaultDataUpdatedContextActor.php | 41 + ...taUpdatedContextGoogleAnalyticsSession.php | 40 + lib/Resource/VaultDataUpdatedData.php | 52 + lib/Resource/VaultDekDecrypted.php | 50 + lib/Resource/VaultDekDecryptedContext.php | 59 + .../VaultDekDecryptedContextActor.php | 41 + ...DecryptedContextGoogleAnalyticsSession.php | 40 + lib/Resource/VaultDekDecryptedData.php | 44 + lib/Resource/VaultDekRead.php | 50 + lib/Resource/VaultDekReadContext.php | 59 + lib/Resource/VaultDekReadContextActor.php | 41 + ...ltDekReadContextGoogleAnalyticsSession.php | 40 + lib/Resource/VaultDekReadData.php | 51 + lib/Resource/VaultDekReadDataActorSource.php | 13 + lib/Resource/VaultKekCreated.php | 50 + lib/Resource/VaultKekCreatedContext.php | 59 + lib/Resource/VaultKekCreatedContextActor.php | 41 + ...ekCreatedContextGoogleAnalyticsSession.php | 40 + lib/Resource/VaultKekCreatedData.php | 48 + lib/Resource/VaultMetadataRead.php | 50 + lib/Resource/VaultMetadataReadContext.php | 59 + .../VaultMetadataReadContextActor.php | 41 + ...adataReadContextGoogleAnalyticsSession.php | 40 + lib/Resource/VaultMetadataReadData.php | 44 + lib/Resource/VaultNamesListed.php | 50 + lib/Resource/VaultNamesListedContext.php | 59 + lib/Resource/VaultNamesListedContextActor.php | 41 + ...mesListedContextGoogleAnalyticsSession.php | 40 + lib/Resource/VaultNamesListedData.php | 40 + lib/Resource/VaultObject.php | 27 - lib/Resource/VerificationChallenge.php | 21 - lib/Resource/VerifyEmailAddress.php | 32 + lib/Resource/VerifyEmailResponse.php | 32 + lib/Resource/Webhook.php | 93 +- lib/Resource/WebhookEndpointJson.php | 63 + lib/Resource/WebhookEndpointJsonStatus.php | 13 + lib/Resource/WebhookResponse.php | 73 +- lib/Resource/WebhooksOrder.php | 14 + lib/Resource/WidgetScope.php | 13 - lib/Resource/WidgetSessionToken.php | 43 + lib/Resource/WidgetSessionTokenResponse.php | 32 + lib/Resource/WidgetSessionTokenScopes.php | 17 + lib/Resource/WidgetTokenResponse.php | 21 - lib/SSO.php | 252 -- lib/Service/AdminPortal.php | 63 + lib/Service/ApiKeys.php | 122 + lib/Service/AuditLogs.php | 257 ++ lib/Service/Authorization.php | 1052 +++++++ lib/Service/Connect.php | 294 ++ lib/Service/DirectorySync.php | 211 ++ lib/Service/Events.php | 61 + lib/Service/FeatureFlags.php | 216 ++ lib/Service/MultiFactorAuth.php | 211 ++ lib/Service/OrganizationDomains.php | 100 + lib/Service/Organizations.php | 212 ++ lib/Service/Pipes.php | 157 + lib/Service/Radar.php | 140 + lib/Service/SSO.php | 252 ++ lib/Service/UserManagement.php | 1377 +++++++++ lib/Service/Webhooks.php | 124 + lib/Service/Widgets.php | 46 + lib/Session/HaliteSessionEncryption.php | 119 - lib/Session/SessionEncryptionInterface.php | 34 - lib/Session/SigningOnlySessionHandler.php | 99 - lib/SessionManager.php | 345 +++ lib/UserManagement.php | 1486 ---------- lib/Util/Request.php | 14 - lib/Vault.php | 366 ++- lib/Version.php | 3 + lib/Webhook.php | 102 - lib/WebhookVerification.php | 120 + lib/Widgets.php | 36 - lib/WorkOS.php | 266 +- phpstan.neon | 6 + script/ci | 26 + tests/ActionsTest.php | 91 + tests/ClientTest.php | 19 + .../action_authentication_denied.json | 37 + .../action_authentication_denied_context.json | 20 + ...n_authentication_denied_context_actor.json | 5 + ...nied_context_google_analytics_session.json | 5 + .../action_authentication_denied_data.json | 11 + .../action_user_registration_denied.json | 36 + ...tion_user_registration_denied_context.json | 20 + ...ser_registration_denied_context_actor.json | 5 + ...nied_context_google_analytics_session.json | 5 + .../action_user_registration_denied_data.json | 10 + tests/Fixtures/add_role_permission.json | 3 + tests/Fixtures/api_key.json | 17 + tests/Fixtures/api_key_created.json | 43 + tests/Fixtures/api_key_created_context.json | 20 + .../api_key_created_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + tests/Fixtures/api_key_created_data.json | 17 + .../Fixtures/api_key_created_data_owner.json | 4 + .../Fixtures/api_key_list_list_metadata.json | 4 + tests/Fixtures/api_key_owner.json | 4 + tests/Fixtures/api_key_revoked.json | 43 + tests/Fixtures/api_key_revoked_context.json | 20 + .../api_key_revoked_context_actor.json | 5 + ...oked_context_google_analytics_session.json | 5 + tests/Fixtures/api_key_revoked_data.json | 17 + .../Fixtures/api_key_revoked_data_owner.json | 4 + .../Fixtures/api_key_validation_response.json | 19 + tests/Fixtures/api_key_with_value.json | 18 + tests/Fixtures/api_key_with_value_owner.json | 4 + .../application_credentials_list_item.json | 8 + tests/Fixtures/assign_role.json | 6 + tests/Fixtures/audit_log_action_json.json | 42 + tests/Fixtures/audit_log_configuration.json | 12 + .../audit_log_configuration_log_stream.json | 7 + tests/Fixtures/audit_log_event.json | 30 + tests/Fixtures/audit_log_event_actor.json | 8 + tests/Fixtures/audit_log_event_context.json | 4 + .../audit_log_event_create_response.json | 3 + tests/Fixtures/audit_log_event_ingestion.json | 33 + tests/Fixtures/audit_log_event_target.json | 8 + tests/Fixtures/audit_log_export_creation.json | 20 + tests/Fixtures/audit_log_export_json.json | 8 + tests/Fixtures/audit_log_schema.json | 33 + tests/Fixtures/audit_log_schema_actor.json | 10 + tests/Fixtures/audit_log_schema_json.json | 36 + .../Fixtures/audit_log_schema_json_actor.json | 5 + .../audit_log_schema_json_target.json | 11 + tests/Fixtures/audit_log_schema_target.json | 11 + tests/Fixtures/audit_logs_retention_json.json | 3 + tests/Fixtures/authenticate_response.json | 39 + .../authenticate_response_impersonator.json | 4 + .../authenticate_response_oauth_token.json | 11 + tests/Fixtures/authentication_challenge.json | 9 + ...hentication_challenge_verify_response.json | 12 + ...hentication_challenges_verify_request.json | 3 + ...hentication_email_verification_failed.json | 38 + ...ion_email_verification_failed_context.json | 20 + ...ail_verification_failed_context_actor.json | 5 + ...iled_context_google_analytics_session.json | 5 + ...cation_email_verification_failed_data.json | 12 + ..._email_verification_failed_data_error.json | 4 + ...tication_email_verification_succeeded.json | 34 + ..._email_verification_succeeded_context.json | 20 + ..._verification_succeeded_context_actor.json | 5 + ...eded_context_google_analytics_session.json | 5 + ...ion_email_verification_succeeded_data.json | 8 + tests/Fixtures/authentication_factor.json | 15 + .../authentication_factor_enrolled.json | 18 + .../authentication_factor_enrolled_sms.json | 3 + .../authentication_factor_enrolled_totp.json | 7 + tests/Fixtures/authentication_factor_sms.json | 3 + .../Fixtures/authentication_factor_totp.json | 4 + ...authentication_factors_create_request.json | 7 + .../authentication_magic_auth_failed.json | 38 + ...hentication_magic_auth_failed_context.json | 20 + ...ation_magic_auth_failed_context_actor.json | 5 + ...iled_context_google_analytics_session.json | 5 + ...authentication_magic_auth_failed_data.json | 12 + ...tication_magic_auth_failed_data_error.json | 4 + .../authentication_magic_auth_succeeded.json | 34 + ...tication_magic_auth_succeeded_context.json | 20 + ...on_magic_auth_succeeded_context_actor.json | 5 + ...eded_context_google_analytics_session.json | 5 + ...hentication_magic_auth_succeeded_data.json | 8 + tests/Fixtures/authentication_mfa_failed.json | 38 + .../authentication_mfa_failed_context.json | 20 + ...thentication_mfa_failed_context_actor.json | 5 + ...iled_context_google_analytics_session.json | 5 + .../authentication_mfa_failed_data.json | 12 + .../authentication_mfa_failed_data_error.json | 4 + .../authentication_mfa_succeeded.json | 34 + .../authentication_mfa_succeeded_context.json | 20 + ...ntication_mfa_succeeded_context_actor.json | 5 + ...eded_context_google_analytics_session.json | 5 + .../authentication_mfa_succeeded_data.json | 8 + .../Fixtures/authentication_oauth_failed.json | 38 + .../authentication_oauth_failed_context.json | 20 + ...entication_oauth_failed_context_actor.json | 5 + ...iled_context_google_analytics_session.json | 5 + .../authentication_oauth_failed_data.json | 12 + ...uthentication_oauth_failed_data_error.json | 4 + .../authentication_oauth_succeeded.json | 34 + ...uthentication_oauth_succeeded_context.json | 20 + ...ication_oauth_succeeded_context_actor.json | 5 + ...eded_context_google_analytics_session.json | 5 + .../authentication_oauth_succeeded_data.json | 8 + .../authentication_passkey_failed.json | 38 + ...authentication_passkey_failed_context.json | 20 + ...tication_passkey_failed_context_actor.json | 5 + ...iled_context_google_analytics_session.json | 5 + .../authentication_passkey_failed_data.json | 12 + ...hentication_passkey_failed_data_error.json | 4 + .../authentication_passkey_succeeded.json | 34 + ...hentication_passkey_succeeded_context.json | 20 + ...ation_passkey_succeeded_context_actor.json | 5 + ...eded_context_google_analytics_session.json | 5 + ...authentication_passkey_succeeded_data.json | 8 + .../authentication_password_failed.json | 38 + ...uthentication_password_failed_context.json | 20 + ...ication_password_failed_context_actor.json | 5 + ...iled_context_google_analytics_session.json | 5 + .../authentication_password_failed_data.json | 12 + ...entication_password_failed_data_error.json | 4 + .../authentication_password_succeeded.json | 34 + ...entication_password_succeeded_context.json | 20 + ...tion_password_succeeded_context_actor.json | 5 + ...eded_context_google_analytics_session.json | 5 + ...uthentication_password_succeeded_data.json | 8 + .../authentication_radar_risk_detected.json | 36 + ...ntication_radar_risk_detected_context.json | 20 + ...ion_radar_risk_detected_context_actor.json | 5 + ...cted_context_google_analytics_session.json | 5 + ...thentication_radar_risk_detected_data.json | 10 + tests/Fixtures/authentication_sso_failed.json | 43 + .../authentication_sso_failed_context.json | 20 + ...thentication_sso_failed_context_actor.json | 5 + ...iled_context_google_analytics_session.json | 5 + .../authentication_sso_failed_data.json | 17 + .../authentication_sso_failed_data_error.json | 4 + .../authentication_sso_failed_data_sso.json | 5 + .../Fixtures/authentication_sso_started.json | 39 + .../authentication_sso_started_context.json | 20 + ...hentication_sso_started_context_actor.json | 5 + ...rted_context_google_analytics_session.json | 5 + .../authentication_sso_started_data.json | 13 + .../authentication_sso_started_data_sso.json | 5 + .../authentication_sso_succeeded.json | 39 + .../authentication_sso_succeeded_context.json | 20 + ...ntication_sso_succeeded_context_actor.json | 5 + ...eded_context_google_analytics_session.json | 5 + .../authentication_sso_succeeded_data.json | 13 + ...authentication_sso_succeeded_data_sso.json | 5 + .../authentication_sso_timed_out.json | 43 + .../authentication_sso_timed_out_context.json | 20 + ...ntication_sso_timed_out_context_actor.json | 5 + ..._out_context_google_analytics_session.json | 5 + .../authentication_sso_timed_out_data.json | 17 + ...thentication_sso_timed_out_data_error.json | 4 + ...authentication_sso_timed_out_data_sso.json | 5 + tests/Fixtures/authorization_check.json | 3 + ...ion_code_session_authenticate_request.json | 9 + tests/Fixtures/authorization_permission.json | 11 + ...ization_permission_list_list_metadata.json | 4 + tests/Fixtures/authorization_resource.json | 12 + ...orization_resource_list_list_metadata.json | 4 + ...horized_connect_application_list_data.json | 23 + ...onnect_application_list_list_metadata.json | 4 + .../challenge_authentication_factor.json | 3 + tests/Fixtures/check_authorization.json | 6 + tests/Fixtures/confirm_email_change.json | 3 + tests/Fixtures/connect_application.json | 14 + ...onnect_application_list_list_metadata.json | 4 + tests/Fixtures/connected_account.json | 13 + tests/Fixtures/connection.json | 21 + tests/Fixtures/connection_activated.json | 45 + .../connection_activated_context.json | 20 + .../connection_activated_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + tests/Fixtures/connection_activated_data.json | 19 + .../connection_activated_data_domain.json | 5 + tests/Fixtures/connection_deactivated.json | 45 + .../connection_deactivated_context.json | 20 + .../connection_deactivated_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + .../Fixtures/connection_deactivated_data.json | 19 + .../connection_deactivated_data_domain.json | 5 + tests/Fixtures/connection_deleted.json | 36 + .../Fixtures/connection_deleted_context.json | 20 + .../connection_deleted_context_actor.json | 5 + ...eted_context_google_analytics_session.json | 5 + tests/Fixtures/connection_deleted_data.json | 10 + tests/Fixtures/connection_domain.json | 5 + .../connection_list_list_metadata.json | 4 + tests/Fixtures/connection_option.json | 3 + ...ion_saml_certificate_renewal_required.json | 38 + ..._certificate_renewal_required_context.json | 20 + ...ficate_renewal_required_context_actor.json | 5 + ...ired_context_google_analytics_session.json | 5 + ...aml_certificate_renewal_required_data.json | 12 + ...ate_renewal_required_data_certificate.json | 5 + ...cate_renewal_required_data_connection.json | 4 + .../connection_saml_certificate_renewed.json | 37 + ...tion_saml_certificate_renewed_context.json | 20 + ...aml_certificate_renewed_context_actor.json | 5 + ...ewed_context_google_analytics_session.json | 5 + ...nection_saml_certificate_renewed_data.json | 11 + ..._certificate_renewed_data_certificate.json | 4 + ...l_certificate_renewed_data_connection.json | 4 + tests/Fixtures/cors_origin_response.json | 7 + tests/Fixtures/create_application_secret.json | 1 + .../create_authorization_permission.json | 6 + .../create_authorization_resource.json | 10 + tests/Fixtures/create_cors_origin.json | 3 + tests/Fixtures/create_m2m_application.json | 11 + .../create_magic_code_and_return.json | 4 + tests/Fixtures/create_oauth_application.json | 19 + .../Fixtures/create_organization_api_key.json | 7 + .../Fixtures/create_organization_domain.json | 4 + tests/Fixtures/create_organization_role.json | 6 + tests/Fixtures/create_password_reset.json | 4 + .../Fixtures/create_password_reset_token.json | 3 + tests/Fixtures/create_redirect_uri.json | 3 + tests/Fixtures/create_role.json | 6 + tests/Fixtures/create_user.json | 13 + .../Fixtures/create_user_invite_options.json | 8 + .../create_user_organization_membership.json | 8 + tests/Fixtures/create_webhook_endpoint.json | 7 + ...ata_integration_access_token_response.json | 1 + ...ta_integration_authorize_url_response.json | 3 + ...ata_integration_authorize_url_request.json | 5 + ...a_integrations_get_user_token_request.json | 4 + .../data_integrations_list_response.json | 42 + .../data_integrations_list_response_data.json | 37 + ..._list_response_data_connected_account.json | 17 + .../device_authorization_response.json | 8 + ...ice_code_session_authenticate_request.json | 8 + tests/Fixtures/directory.json | 19 + tests/Fixtures/directory_group.json | 13 + .../directory_group_list_list_metadata.json | 4 + .../directory_list_list_metadata.json | 4 + tests/Fixtures/directory_metadata.json | 7 + tests/Fixtures/directory_metadata_user.json | 4 + tests/Fixtures/directory_user.json | 37 + tests/Fixtures/directory_user_email.json | 5 + .../directory_user_list_list_metadata.json | 4 + .../Fixtures/directory_user_with_groups.json | 52 + .../directory_user_with_groups_email.json | 5 + tests/Fixtures/dsync_activated.json | 44 + tests/Fixtures/dsync_activated_context.json | 20 + .../dsync_activated_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + tests/Fixtures/dsync_activated_data.json | 18 + .../Fixtures/dsync_activated_data_domain.json | 5 + tests/Fixtures/dsync_deactivated.json | 44 + tests/Fixtures/dsync_deactivated_context.json | 20 + .../dsync_deactivated_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + tests/Fixtures/dsync_deactivated_data.json | 18 + .../dsync_deactivated_data_domain.json | 5 + tests/Fixtures/dsync_deleted.json | 36 + tests/Fixtures/dsync_deleted_context.json | 20 + .../Fixtures/dsync_deleted_context_actor.json | 5 + ...eted_context_google_analytics_session.json | 5 + tests/Fixtures/dsync_deleted_data.json | 10 + tests/Fixtures/dsync_group_created.json | 39 + .../Fixtures/dsync_group_created_context.json | 20 + .../dsync_group_created_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + tests/Fixtures/dsync_group_created_data.json | 13 + tests/Fixtures/dsync_group_deleted.json | 39 + .../Fixtures/dsync_group_deleted_context.json | 20 + .../dsync_group_deleted_context_actor.json | 5 + ...eted_context_google_analytics_session.json | 5 + tests/Fixtures/dsync_group_deleted_data.json | 13 + tests/Fixtures/dsync_group_updated.json | 42 + .../Fixtures/dsync_group_updated_context.json | 20 + .../dsync_group_updated_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + tests/Fixtures/dsync_group_updated_data.json | 16 + tests/Fixtures/dsync_group_user_added.json | 79 + .../dsync_group_user_added_context.json | 20 + .../dsync_group_user_added_context_actor.json | 5 + ...dded_context_google_analytics_session.json | 5 + .../Fixtures/dsync_group_user_added_data.json | 53 + .../dsync_group_user_added_data_group.json | 13 + .../dsync_group_user_added_data_user.json | 37 + ...sync_group_user_added_data_user_email.json | 5 + ...dsync_group_user_added_data_user_role.json | 3 + tests/Fixtures/dsync_group_user_removed.json | 79 + .../dsync_group_user_removed_context.json | 20 + ...sync_group_user_removed_context_actor.json | 5 + ...oved_context_google_analytics_session.json | 5 + .../dsync_group_user_removed_data.json | 53 + .../dsync_group_user_removed_data_group.json | 13 + .../dsync_group_user_removed_data_user.json | 37 + ...nc_group_user_removed_data_user_email.json | 5 + ...ync_group_user_removed_data_user_role.json | 3 + tests/Fixtures/dsync_user_created.json | 63 + .../Fixtures/dsync_user_created_context.json | 20 + .../dsync_user_created_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + tests/Fixtures/dsync_user_created_data.json | 37 + .../dsync_user_created_data_email.json | 5 + .../dsync_user_created_data_role.json | 3 + tests/Fixtures/dsync_user_deleted.json | 63 + .../Fixtures/dsync_user_deleted_context.json | 20 + .../dsync_user_deleted_context_actor.json | 5 + ...eted_context_google_analytics_session.json | 5 + tests/Fixtures/dsync_user_deleted_data.json | 37 + .../dsync_user_deleted_data_email.json | 5 + .../dsync_user_deleted_data_role.json | 3 + tests/Fixtures/dsync_user_updated.json | 66 + .../Fixtures/dsync_user_updated_context.json | 20 + .../dsync_user_updated_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + tests/Fixtures/dsync_user_updated_data.json | 40 + .../dsync_user_updated_data_email.json | 5 + .../dsync_user_updated_data_role.json | 3 + tests/Fixtures/email_change.json | 23 + tests/Fixtures/email_change_confirmation.json | 20 + .../email_change_confirmation_user.json | 17 + tests/Fixtures/email_verification.json | 10 + ...ion_code_session_authenticate_request.json | 10 + .../Fixtures/email_verification_created.json | 35 + .../email_verification_created_context.json | 20 + ...il_verification_created_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + .../email_verification_created_data.json | 9 + .../enroll_user_authentication_factor.json | 6 + tests/Fixtures/event_context.json | 20 + tests/Fixtures/event_context_actor.json | 5 + ...vent_context_google_analytics_session.json | 5 + tests/Fixtures/event_list_list_metadata.json | 3 + tests/Fixtures/event_schema.json | 32 + .../external_auth_complete_response.json | 3 + tests/Fixtures/feature_flag.json | 19 + tests/Fixtures/feature_flag_owner.json | 5 + tests/Fixtures/flag.json | 19 + tests/Fixtures/flag_created.json | 34 + tests/Fixtures/flag_created_context.json | 8 + .../Fixtures/flag_created_context_actor.json | 5 + tests/Fixtures/flag_created_data.json | 20 + tests/Fixtures/flag_created_data_owner.json | 5 + tests/Fixtures/flag_deleted.json | 34 + tests/Fixtures/flag_deleted_context.json | 8 + .../Fixtures/flag_deleted_context_actor.json | 5 + tests/Fixtures/flag_deleted_data.json | 20 + tests/Fixtures/flag_deleted_data_owner.json | 5 + tests/Fixtures/flag_list_list_metadata.json | 4 + tests/Fixtures/flag_owner.json | 5 + tests/Fixtures/flag_rule_updated.json | 72 + tests/Fixtures/flag_rule_updated_context.json | 46 + .../flag_rule_updated_context_actor.json | 5 + ...ule_updated_context_configured_target.json | 14 + ...ontext_configured_target_organization.json | 4 + ...pdated_context_configured_target_user.json | 4 + ...le_updated_context_previous_attribute.json | 23 + ...ed_context_previous_attribute_context.json | 17 + ...s_attribute_context_configured_target.json | 14 + ...ontext_configured_target_organization.json | 4 + ...ribute_context_configured_target_user.json | 4 + ...dated_context_previous_attribute_data.json | 4 + tests/Fixtures/flag_rule_updated_data.json | 20 + .../flag_rule_updated_data_owner.json | 5 + tests/Fixtures/flag_updated.json | 46 + tests/Fixtures/flag_updated_context.json | 20 + .../Fixtures/flag_updated_context_actor.json | 5 + ...ag_updated_context_previous_attribute.json | 12 + ...dated_context_previous_attribute_data.json | 10 + tests/Fixtures/flag_updated_data.json | 20 + tests/Fixtures/flag_updated_data_owner.json | 5 + tests/Fixtures/generate_link.json | 15 + tests/Fixtures/intent_options.json | 6 + tests/Fixtures/invitation.json | 16 + tests/Fixtures/invitation_accepted.json | 40 + .../Fixtures/invitation_accepted_context.json | 20 + .../invitation_accepted_context_actor.json | 5 + ...pted_context_google_analytics_session.json | 5 + tests/Fixtures/invitation_accepted_data.json | 14 + tests/Fixtures/invitation_created.json | 40 + .../Fixtures/invitation_created_context.json | 20 + .../invitation_created_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + tests/Fixtures/invitation_created_data.json | 14 + tests/Fixtures/invitation_resent.json | 40 + tests/Fixtures/invitation_resent_context.json | 20 + .../invitation_resent_context_actor.json | 5 + ...sent_context_google_analytics_session.json | 5 + tests/Fixtures/invitation_resent_data.json | 14 + tests/Fixtures/invitation_revoked.json | 40 + .../Fixtures/invitation_revoked_context.json | 20 + .../invitation_revoked_context_actor.json | 5 + ...oked_context_google_analytics_session.json | 5 + tests/Fixtures/invitation_revoked_data.json | 14 + tests/Fixtures/jwks_response.json | 16 + tests/Fixtures/jwks_response_keys.json | 12 + tests/Fixtures/jwt_template_response.json | 6 + tests/Fixtures/list.json | 20 + tests/Fixtures/list_api_key.json | 25 + .../Fixtures/list_audit_log_action_json.json | 50 + .../Fixtures/list_audit_log_schema_json.json | 44 + .../Fixtures/list_authentication_factor.json | 23 + .../list_authorization_permission.json | 19 + .../Fixtures/list_authorization_resource.json | 20 + ...horized_connect_application_list_data.json | 31 + tests/Fixtures/list_connect_application.json | 22 + tests/Fixtures/list_connection.json | 29 + tests/Fixtures/list_data.json | 15 + tests/Fixtures/list_directory.json | 27 + tests/Fixtures/list_directory_group.json | 21 + .../list_directory_user_with_groups.json | 60 + tests/Fixtures/list_event_schema.json | 40 + tests/Fixtures/list_flag.json | 27 + tests/Fixtures/list_organization.json | 35 + tests/Fixtures/list_role_assignment.json | 22 + tests/Fixtures/list_user.json | 25 + tests/Fixtures/list_user_invite.json | 24 + .../list_user_organization_membership.json | 27 + ...rganization_membership_base_list_data.json | 24 + .../list_user_sessions_list_item.json | 26 + .../Fixtures/list_webhook_endpoint_json.json | 21 + tests/Fixtures/magic_auth.json | 10 + ...uth_code_session_authenticate_request.json | 11 + tests/Fixtures/magic_auth_created.json | 35 + .../Fixtures/magic_auth_created_context.json | 20 + .../magic_auth_created_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + tests/Fixtures/magic_auth_created_data.json | 9 + ...mfa_totp_session_authenticate_request.json | 11 + .../new_connect_application_secret.json | 9 + tests/Fixtures/organization.json | 27 + tests/Fixtures/organization_created.json | 52 + .../organization_created_context.json | 20 + .../organization_created_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + tests/Fixtures/organization_created_data.json | 26 + .../organization_created_data_domain.json | 12 + tests/Fixtures/organization_deleted.json | 52 + .../organization_deleted_context.json | 20 + .../organization_deleted_context_actor.json | 5 + ...eted_context_google_analytics_session.json | 5 + tests/Fixtures/organization_deleted_data.json | 26 + .../organization_deleted_data_domain.json | 12 + tests/Fixtures/organization_domain.json | 12 + .../Fixtures/organization_domain_created.json | 38 + .../organization_domain_created_context.json | 20 + ...nization_domain_created_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + .../organization_domain_created_data.json | 12 + tests/Fixtures/organization_domain_data.json | 4 + .../Fixtures/organization_domain_deleted.json | 38 + .../organization_domain_deleted_context.json | 20 + ...nization_domain_deleted_context_actor.json | 5 + ...eted_context_google_analytics_session.json | 5 + .../organization_domain_deleted_data.json | 12 + .../organization_domain_stand_alone.json | 12 + .../Fixtures/organization_domain_updated.json | 38 + .../organization_domain_updated_context.json | 20 + ...nization_domain_updated_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + .../organization_domain_updated_data.json | 12 + ...ganization_domain_verification_failed.json | 41 + ...on_domain_verification_failed_context.json | 20 + ...ain_verification_failed_context_actor.json | 5 + ...iled_context_google_analytics_session.json | 5 + ...ation_domain_verification_failed_data.json | 15 + ...ation_failed_data_organization_domain.json | 12 + .../organization_domain_verified.json | 38 + .../organization_domain_verified_context.json | 20 + ...ization_domain_verified_context_actor.json | 5 + ...fied_context_google_analytics_session.json | 5 + .../organization_domain_verified_data.json | 12 + tests/Fixtures/organization_input.json | 17 + .../organization_list_list_metadata.json | 4 + tests/Fixtures/organization_membership.json | 19 + .../organization_membership_created.json | 48 + ...ganization_membership_created_context.json | 20 + ...tion_membership_created_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + .../organization_membership_created_data.json | 22 + .../organization_membership_deleted.json | 48 + ...ganization_membership_deleted_context.json | 20 + ...tion_membership_deleted_context_actor.json | 5 + ...eted_context_google_analytics_session.json | 5 + .../organization_membership_deleted_data.json | 22 + .../organization_membership_updated.json | 48 + ...ganization_membership_updated_context.json | 20 + ...tion_membership_updated_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + .../organization_membership_updated_data.json | 22 + tests/Fixtures/organization_role_created.json | 40 + .../organization_role_created_context.json | 20 + ...ganization_role_created_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + .../organization_role_created_data.json | 14 + tests/Fixtures/organization_role_deleted.json | 40 + .../organization_role_deleted_context.json | 20 + ...ganization_role_deleted_context_actor.json | 5 + ...eted_context_google_analytics_session.json | 5 + .../organization_role_deleted_data.json | 14 + tests/Fixtures/organization_role_updated.json | 40 + .../organization_role_updated_context.json | 20 + ...ganization_role_updated_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + .../organization_role_updated_data.json | 14 + ...election_session_authenticate_request.json | 10 + tests/Fixtures/organization_updated.json | 52 + .../organization_updated_context.json | 20 + .../organization_updated_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + tests/Fixtures/organization_updated_data.json | 26 + .../organization_updated_data_domain.json | 12 + tests/Fixtures/password_reset.json | 10 + tests/Fixtures/password_reset_created.json | 34 + .../password_reset_created_context.json | 20 + .../password_reset_created_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + .../Fixtures/password_reset_created_data.json | 8 + tests/Fixtures/password_reset_succeeded.json | 34 + .../password_reset_succeeded_context.json | 20 + ...assword_reset_succeeded_context_actor.json | 5 + ...eded_context_google_analytics_session.json | 5 + .../password_reset_succeeded_data.json | 8 + ...password_session_authenticate_request.json | 11 + tests/Fixtures/permission.json | 11 + tests/Fixtures/permission_created.json | 36 + .../Fixtures/permission_created_context.json | 20 + .../permission_created_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + tests/Fixtures/permission_created_data.json | 10 + tests/Fixtures/permission_deleted.json | 36 + .../Fixtures/permission_deleted_context.json | 20 + .../permission_deleted_context_actor.json | 5 + ...eted_context_google_analytics_session.json | 5 + tests/Fixtures/permission_deleted_data.json | 10 + tests/Fixtures/permission_updated.json | 36 + .../Fixtures/permission_updated_context.json | 20 + .../permission_updated_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + tests/Fixtures/permission_updated_data.json | 10 + tests/Fixtures/portal_link_response.json | 3 + tests/Fixtures/profile.json | 29 + ...r_list_entry_already_present_response.json | 3 + .../radar_standalone_assess_request.json | 9 + ...alone_delete_radar_list_entry_request.json | 3 + tests/Fixtures/radar_standalone_response.json | 7 + ...andalone_update_radar_attempt_request.json | 4 + ..._standalone_update_radar_list_request.json | 3 + tests/Fixtures/redirect_uri.json | 8 + tests/Fixtures/redirect_uri_input.json | 4 + ...sh_token_session_authenticate_request.json | 10 + tests/Fixtures/remove_role.json | 6 + .../Fixtures/resend_user_invite_options.json | 3 + tests/Fixtures/reset_password_response.json | 19 + tests/Fixtures/revoke_session.json | 4 + tests/Fixtures/role.json | 15 + tests/Fixtures/role_assignment.json | 14 + .../role_assignment_list_list_metadata.json | 4 + tests/Fixtures/role_assignment_resource.json | 5 + tests/Fixtures/role_created.json | 37 + tests/Fixtures/role_created_context.json | 20 + .../Fixtures/role_created_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + tests/Fixtures/role_created_data.json | 11 + tests/Fixtures/role_deleted.json | 37 + tests/Fixtures/role_deleted_context.json | 20 + .../Fixtures/role_deleted_context_actor.json | 5 + ...eted_context_google_analytics_session.json | 5 + tests/Fixtures/role_deleted_data.json | 11 + tests/Fixtures/role_list.json | 20 + tests/Fixtures/role_updated.json | 37 + tests/Fixtures/role_updated_context.json | 20 + .../Fixtures/role_updated_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + tests/Fixtures/role_updated_data.json | 11 + tests/Fixtures/send_email_change.json | 3 + .../send_verification_email_response.json | 19 + tests/Fixtures/session_created.json | 44 + tests/Fixtures/session_created_context.json | 20 + .../session_created_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + tests/Fixtures/session_created_data.json | 18 + .../session_created_data_impersonator.json | 4 + tests/Fixtures/session_revoked.json | 44 + tests/Fixtures/session_revoked_context.json | 20 + .../session_revoked_context_actor.json | 5 + ...oked_context_google_analytics_session.json | 5 + tests/Fixtures/session_revoked_data.json | 18 + .../session_revoked_data_impersonator.json | 4 + tests/Fixtures/set_role_permissions.json | 8 + tests/Fixtures/slim_role.json | 3 + .../Fixtures/sso_authorize_url_response.json | 3 + .../sso_device_authorization_request.json | 3 + tests/Fixtures/sso_intent_options.json | 4 + .../sso_logout_authorize_request.json | 3 + .../sso_logout_authorize_response.json | 4 + tests/Fixtures/sso_token_response.json | 45 + .../sso_token_response_oauth_token.json | 11 + tests/Fixtures/token_query.json | 6 + .../Fixtures/update_audit_logs_retention.json | 3 + .../update_authorization_permission.json | 4 + .../update_authorization_resource.json | 7 + tests/Fixtures/update_jwt_template.json | 3 + tests/Fixtures/update_oauth_application.json | 15 + tests/Fixtures/update_organization.json | 18 + tests/Fixtures/update_organization_role.json | 4 + tests/Fixtures/update_role.json | 4 + tests/Fixtures/update_user.json | 14 + .../update_user_organization_membership.json | 6 + tests/Fixtures/update_webhook_endpoint.json | 8 + tests/Fixtures/user.json | 17 + ...authentication_factor_enroll_response.json | 29 + ...hentication_factor_list_list_metadata.json | 4 + tests/Fixtures/user_consent_option.json | 11 + .../Fixtures/user_consent_option_choice.json | 4 + tests/Fixtures/user_created.json | 43 + tests/Fixtures/user_created_context.json | 20 + .../Fixtures/user_created_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + tests/Fixtures/user_created_data.json | 17 + tests/Fixtures/user_deleted.json | 43 + tests/Fixtures/user_deleted_context.json | 20 + .../Fixtures/user_deleted_context_actor.json | 5 + ...eted_context_google_analytics_session.json | 5 + tests/Fixtures/user_deleted_data.json | 17 + tests/Fixtures/user_identities_get_item.json | 5 + tests/Fixtures/user_invite.json | 16 + tests/Fixtures/user_list_list_metadata.json | 4 + .../user_management_login_request.json | 26 + tests/Fixtures/user_object.json | 10 + .../user_organization_membership.json | 19 + ...rganization_membership_base_list_data.json | 16 + ...on_membership_base_list_list_metadata.json | 4 + .../Fixtures/user_sessions_impersonator.json | 4 + tests/Fixtures/user_sessions_list_item.json | 18 + tests/Fixtures/user_updated.json | 43 + tests/Fixtures/user_updated_context.json | 20 + .../Fixtures/user_updated_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + tests/Fixtures/user_updated_data.json | 17 + tests/Fixtures/validate_api_key.json | 3 + ...vault_byok_key_verification_completed.json | 31 + ...ok_key_verification_completed_context.json | 20 + ..._verification_completed_context_actor.json | 5 + ...eted_context_google_analytics_session.json | 5 + ..._byok_key_verification_completed_data.json | 5 + tests/Fixtures/vault_data_created.json | 36 + .../Fixtures/vault_data_created_context.json | 20 + .../vault_data_created_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + tests/Fixtures/vault_data_created_data.json | 10 + tests/Fixtures/vault_data_deleted.json | 32 + .../Fixtures/vault_data_deleted_context.json | 20 + .../vault_data_deleted_context_actor.json | 5 + ...eted_context_google_analytics_session.json | 5 + tests/Fixtures/vault_data_deleted_data.json | 6 + tests/Fixtures/vault_data_read.json | 33 + tests/Fixtures/vault_data_read_context.json | 20 + .../vault_data_read_context_actor.json | 5 + ...read_context_google_analytics_session.json | 5 + tests/Fixtures/vault_data_read_data.json | 7 + tests/Fixtures/vault_data_updated.json | 36 + .../Fixtures/vault_data_updated_context.json | 20 + .../vault_data_updated_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + tests/Fixtures/vault_data_updated_data.json | 10 + tests/Fixtures/vault_dek_decrypted.json | 32 + .../Fixtures/vault_dek_decrypted_context.json | 20 + .../vault_dek_decrypted_context_actor.json | 5 + ...pted_context_google_analytics_session.json | 5 + tests/Fixtures/vault_dek_decrypted_data.json | 6 + tests/Fixtures/vault_dek_read.json | 37 + tests/Fixtures/vault_dek_read_context.json | 20 + .../vault_dek_read_context_actor.json | 5 + ...read_context_google_analytics_session.json | 5 + tests/Fixtures/vault_dek_read_data.json | 11 + tests/Fixtures/vault_kek_created.json | 33 + tests/Fixtures/vault_kek_created_context.json | 20 + .../vault_kek_created_context_actor.json | 5 + ...ated_context_google_analytics_session.json | 5 + tests/Fixtures/vault_kek_created_data.json | 7 + tests/Fixtures/vault_metadata_read.json | 32 + .../Fixtures/vault_metadata_read_context.json | 20 + .../vault_metadata_read_context_actor.json | 5 + ...read_context_google_analytics_session.json | 5 + tests/Fixtures/vault_metadata_read_data.json | 6 + tests/Fixtures/vault_names_listed.json | 31 + .../Fixtures/vault_names_listed_context.json | 20 + .../vault_names_listed_context_actor.json | 5 + ...sted_context_google_analytics_session.json | 5 + tests/Fixtures/vault_names_listed_data.json | 5 + tests/Fixtures/verify_email_address.json | 3 + tests/Fixtures/verify_email_response.json | 19 + tests/Fixtures/webhook_endpoint_json.json | 13 + .../webhook_endpoint_list_list_metadata.json | 4 + tests/Fixtures/widget_session_token.json | 7 + .../widget_session_token_response.json | 3 + tests/PKCEHelperTest.php | 161 + tests/PasswordlessTest.php | 54 + tests/Service/AdminPortalTest.php | 30 + tests/Service/ApiKeysTest.php | 89 + tests/Service/AuditLogsTest.php | 148 + tests/Service/AuthorizationTest.php | 527 ++++ tests/Service/ConnectTest.php | 157 + tests/Service/DirectorySyncTest.php | 140 + tests/Service/EventsTest.php | 53 + tests/Service/FeatureFlagsTest.php | 142 + tests/Service/MultiFactorAuthTest.php | 127 + tests/Service/OrganizationDomainsTest.php | 69 + tests/Service/OrganizationsTest.php | 131 + tests/Service/PipesTest.php | 79 + tests/Service/RadarTest.php | 67 + tests/Service/RuntimeBehaviorTest.php | 151 + tests/Service/SSOTest.php | 142 + tests/Service/UserManagementTest.php | 688 +++++ tests/Service/WebhooksTest.php | 89 + tests/Service/WidgetsTest.php | 30 + tests/SessionManagerTest.php | 140 + tests/TestHelper.php | 139 +- tests/VaultTest.php | 123 + tests/WebhookVerificationTest.php | 89 + tests/WorkOS/AuditLogsTest.php | 469 --- tests/WorkOS/ClientTest.php | 264 -- tests/WorkOS/CookieSessionTest.php | 252 -- tests/WorkOS/DirectorySyncTest.php | 794 ----- tests/WorkOS/MFATest.php | 384 --- tests/WorkOS/OrganizationsTest.php | 568 ---- tests/WorkOS/PaginatedResourceTest.php | 229 -- tests/WorkOS/PasswordlessTest.php | 91 - tests/WorkOS/PortalTest.php | 210 -- tests/WorkOS/RBACTest.php | 618 ---- tests/WorkOS/Resource/WebhookResponseTest.php | 149 - tests/WorkOS/SSOTest.php | 421 --- .../Session/HaliteSessionEncryptionTest.php | 175 -- .../Session/SigningOnlySessionHandlerTest.php | 277 -- tests/WorkOS/UserManagementTest.php | 2602 ----------------- tests/WorkOS/VaultTest.php | 205 -- tests/WorkOS/WebhookTest.php | 118 - tests/WorkOS/WidgetsTest.php | 61 - tests/WorkOS/WorkOSTest.php | 59 - tests/bootstrap.php | 2 + 1589 files changed, 56219 insertions(+), 14324 deletions(-) create mode 100644 .php-cs-fixer.dist.php create mode 100644 docs/V5_MIGRATION_GUIDE.md create mode 100644 lib/Actions.php delete mode 100644 lib/AuditLogs.php delete mode 100644 lib/Client.php delete mode 100644 lib/CookieSession.php delete mode 100644 lib/DirectorySync.php create mode 100644 lib/Exception/ApiException.php create mode 100644 lib/Exception/ConflictException.php create mode 100644 lib/Exception/ConnectionException.php create mode 100644 lib/Exception/RateLimitExceededException.php create mode 100644 lib/Exception/TimeoutException.php create mode 100644 lib/Exception/UnprocessableEntityException.php create mode 100644 lib/HttpClient.php delete mode 100644 lib/MFA.php delete mode 100644 lib/Organizations.php create mode 100644 lib/PKCEHelper.php create mode 100644 lib/PaginatedResponse.php delete mode 100644 lib/Portal.php delete mode 100644 lib/RBAC.php delete mode 100644 lib/RequestClient/CurlRequestClient.php delete mode 100644 lib/RequestClient/RequestClientInterface.php create mode 100644 lib/RequestOptions.php create mode 100644 lib/Resource/ActionAuthenticationDenied.php create mode 100644 lib/Resource/ActionAuthenticationDeniedContext.php create mode 100644 lib/Resource/ActionAuthenticationDeniedContextActor.php create mode 100644 lib/Resource/ActionAuthenticationDeniedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/ActionAuthenticationDeniedData.php create mode 100644 lib/Resource/ActionUserRegistrationDenied.php create mode 100644 lib/Resource/ActionUserRegistrationDeniedContext.php create mode 100644 lib/Resource/ActionUserRegistrationDeniedContextActor.php create mode 100644 lib/Resource/ActionUserRegistrationDeniedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/ActionUserRegistrationDeniedData.php create mode 100644 lib/Resource/AddRolePermission.php create mode 100644 lib/Resource/ApiKey.php create mode 100644 lib/Resource/ApiKeyCreated.php create mode 100644 lib/Resource/ApiKeyCreatedContext.php create mode 100644 lib/Resource/ApiKeyCreatedContextActor.php create mode 100644 lib/Resource/ApiKeyCreatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/ApiKeyCreatedData.php create mode 100644 lib/Resource/ApiKeyCreatedDataOwner.php create mode 100644 lib/Resource/ApiKeyOwner.php create mode 100644 lib/Resource/ApiKeyRevoked.php create mode 100644 lib/Resource/ApiKeyRevokedContext.php create mode 100644 lib/Resource/ApiKeyRevokedContextActor.php create mode 100644 lib/Resource/ApiKeyRevokedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/ApiKeyRevokedData.php create mode 100644 lib/Resource/ApiKeyRevokedDataOwner.php create mode 100644 lib/Resource/ApiKeyValidationResponse.php create mode 100644 lib/Resource/ApiKeyWithValue.php create mode 100644 lib/Resource/ApiKeyWithValueOwner.php create mode 100644 lib/Resource/ApplicationCredentialsListItem.php create mode 100644 lib/Resource/ApplicationsOrder.php create mode 100644 lib/Resource/AssignRole.php create mode 100644 lib/Resource/AuditLogActionJson.php create mode 100644 lib/Resource/AuditLogConfiguration.php create mode 100644 lib/Resource/AuditLogConfigurationLogStream.php create mode 100644 lib/Resource/AuditLogConfigurationLogStreamState.php create mode 100644 lib/Resource/AuditLogConfigurationLogStreamType.php create mode 100644 lib/Resource/AuditLogConfigurationState.php delete mode 100644 lib/Resource/AuditLogCreateEventStatus.php create mode 100644 lib/Resource/AuditLogEvent.php create mode 100644 lib/Resource/AuditLogEventActor.php create mode 100644 lib/Resource/AuditLogEventContext.php create mode 100644 lib/Resource/AuditLogEventCreateResponse.php create mode 100644 lib/Resource/AuditLogEventIngestion.php create mode 100644 lib/Resource/AuditLogEventTarget.php delete mode 100644 lib/Resource/AuditLogExport.php create mode 100644 lib/Resource/AuditLogExportCreation.php create mode 100644 lib/Resource/AuditLogExportJson.php create mode 100644 lib/Resource/AuditLogExportJsonState.php create mode 100644 lib/Resource/AuditLogSchema.php create mode 100644 lib/Resource/AuditLogSchemaActor.php create mode 100644 lib/Resource/AuditLogSchemaJson.php create mode 100644 lib/Resource/AuditLogSchemaJsonActor.php create mode 100644 lib/Resource/AuditLogSchemaJsonTarget.php create mode 100644 lib/Resource/AuditLogSchemaTarget.php create mode 100644 lib/Resource/AuditLogsOrder.php create mode 100644 lib/Resource/AuditLogsRetentionJson.php create mode 100644 lib/Resource/AuthenticateResponse.php create mode 100644 lib/Resource/AuthenticateResponseAuthenticationMethod.php create mode 100644 lib/Resource/AuthenticateResponseImpersonator.php create mode 100644 lib/Resource/AuthenticateResponseOAuthToken.php create mode 100644 lib/Resource/AuthenticationChallenge.php delete mode 100644 lib/Resource/AuthenticationChallengeSms.php delete mode 100644 lib/Resource/AuthenticationChallengeTotp.php create mode 100644 lib/Resource/AuthenticationChallengeVerifyResponse.php create mode 100644 lib/Resource/AuthenticationChallengesVerifyRequest.php create mode 100644 lib/Resource/AuthenticationEmailVerificationFailed.php create mode 100644 lib/Resource/AuthenticationEmailVerificationFailedContext.php create mode 100644 lib/Resource/AuthenticationEmailVerificationFailedContextActor.php create mode 100644 lib/Resource/AuthenticationEmailVerificationFailedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/AuthenticationEmailVerificationFailedData.php create mode 100644 lib/Resource/AuthenticationEmailVerificationFailedDataError.php create mode 100644 lib/Resource/AuthenticationEmailVerificationSucceeded.php create mode 100644 lib/Resource/AuthenticationEmailVerificationSucceededContext.php create mode 100644 lib/Resource/AuthenticationEmailVerificationSucceededContextActor.php create mode 100644 lib/Resource/AuthenticationEmailVerificationSucceededContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/AuthenticationEmailVerificationSucceededData.php create mode 100644 lib/Resource/AuthenticationFactor.php delete mode 100644 lib/Resource/AuthenticationFactorAndChallengeTotp.php create mode 100644 lib/Resource/AuthenticationFactorEnrolled.php create mode 100644 lib/Resource/AuthenticationFactorEnrolledSms.php create mode 100644 lib/Resource/AuthenticationFactorEnrolledTotp.php create mode 100644 lib/Resource/AuthenticationFactorEnrolledType.php create mode 100644 lib/Resource/AuthenticationFactorType.php create mode 100644 lib/Resource/AuthenticationFactorsCreateRequest.php create mode 100644 lib/Resource/AuthenticationFactorsCreateRequestType.php create mode 100644 lib/Resource/AuthenticationMFAFailed.php create mode 100644 lib/Resource/AuthenticationMFAFailedContext.php create mode 100644 lib/Resource/AuthenticationMFAFailedContextActor.php create mode 100644 lib/Resource/AuthenticationMFAFailedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/AuthenticationMFAFailedData.php create mode 100644 lib/Resource/AuthenticationMFAFailedDataError.php create mode 100644 lib/Resource/AuthenticationMFASucceeded.php create mode 100644 lib/Resource/AuthenticationMFASucceededContext.php create mode 100644 lib/Resource/AuthenticationMFASucceededContextActor.php create mode 100644 lib/Resource/AuthenticationMFASucceededContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/AuthenticationMFASucceededData.php create mode 100644 lib/Resource/AuthenticationMagicAuthFailed.php create mode 100644 lib/Resource/AuthenticationMagicAuthFailedContext.php create mode 100644 lib/Resource/AuthenticationMagicAuthFailedContextActor.php create mode 100644 lib/Resource/AuthenticationMagicAuthFailedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/AuthenticationMagicAuthFailedData.php create mode 100644 lib/Resource/AuthenticationMagicAuthFailedDataError.php create mode 100644 lib/Resource/AuthenticationMagicAuthSucceeded.php create mode 100644 lib/Resource/AuthenticationMagicAuthSucceededContext.php create mode 100644 lib/Resource/AuthenticationMagicAuthSucceededContextActor.php create mode 100644 lib/Resource/AuthenticationMagicAuthSucceededContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/AuthenticationMagicAuthSucceededData.php create mode 100644 lib/Resource/AuthenticationOAuthFailed.php create mode 100644 lib/Resource/AuthenticationOAuthFailedContext.php create mode 100644 lib/Resource/AuthenticationOAuthFailedContextActor.php create mode 100644 lib/Resource/AuthenticationOAuthFailedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/AuthenticationOAuthFailedData.php create mode 100644 lib/Resource/AuthenticationOAuthFailedDataError.php create mode 100644 lib/Resource/AuthenticationOAuthSucceeded.php create mode 100644 lib/Resource/AuthenticationOAuthSucceededContext.php create mode 100644 lib/Resource/AuthenticationOAuthSucceededContextActor.php create mode 100644 lib/Resource/AuthenticationOAuthSucceededContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/AuthenticationOAuthSucceededData.php create mode 100644 lib/Resource/AuthenticationPasskeyFailed.php create mode 100644 lib/Resource/AuthenticationPasskeyFailedContext.php create mode 100644 lib/Resource/AuthenticationPasskeyFailedContextActor.php create mode 100644 lib/Resource/AuthenticationPasskeyFailedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/AuthenticationPasskeyFailedData.php create mode 100644 lib/Resource/AuthenticationPasskeyFailedDataError.php create mode 100644 lib/Resource/AuthenticationPasskeySucceeded.php create mode 100644 lib/Resource/AuthenticationPasskeySucceededContext.php create mode 100644 lib/Resource/AuthenticationPasskeySucceededContextActor.php create mode 100644 lib/Resource/AuthenticationPasskeySucceededContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/AuthenticationPasskeySucceededData.php create mode 100644 lib/Resource/AuthenticationPasswordFailed.php create mode 100644 lib/Resource/AuthenticationPasswordFailedContext.php create mode 100644 lib/Resource/AuthenticationPasswordFailedContextActor.php create mode 100644 lib/Resource/AuthenticationPasswordFailedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/AuthenticationPasswordFailedData.php create mode 100644 lib/Resource/AuthenticationPasswordFailedDataError.php create mode 100644 lib/Resource/AuthenticationPasswordSucceeded.php create mode 100644 lib/Resource/AuthenticationPasswordSucceededContext.php create mode 100644 lib/Resource/AuthenticationPasswordSucceededContextActor.php create mode 100644 lib/Resource/AuthenticationPasswordSucceededContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/AuthenticationPasswordSucceededData.php create mode 100644 lib/Resource/AuthenticationRadarRiskDetected.php create mode 100644 lib/Resource/AuthenticationRadarRiskDetectedContext.php create mode 100644 lib/Resource/AuthenticationRadarRiskDetectedContextActor.php create mode 100644 lib/Resource/AuthenticationRadarRiskDetectedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/AuthenticationRadarRiskDetectedData.php create mode 100644 lib/Resource/AuthenticationRadarRiskDetectedDataAction.php delete mode 100644 lib/Resource/AuthenticationResponse.php create mode 100644 lib/Resource/AuthenticationSSOFailed.php create mode 100644 lib/Resource/AuthenticationSSOFailedContext.php create mode 100644 lib/Resource/AuthenticationSSOFailedContextActor.php create mode 100644 lib/Resource/AuthenticationSSOFailedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/AuthenticationSSOFailedData.php create mode 100644 lib/Resource/AuthenticationSSOFailedDataError.php create mode 100644 lib/Resource/AuthenticationSSOFailedDataSSO.php create mode 100644 lib/Resource/AuthenticationSSOStarted.php create mode 100644 lib/Resource/AuthenticationSSOStartedContext.php create mode 100644 lib/Resource/AuthenticationSSOStartedContextActor.php create mode 100644 lib/Resource/AuthenticationSSOStartedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/AuthenticationSSOStartedData.php create mode 100644 lib/Resource/AuthenticationSSOStartedDataSSO.php create mode 100644 lib/Resource/AuthenticationSSOSucceeded.php create mode 100644 lib/Resource/AuthenticationSSOSucceededContext.php create mode 100644 lib/Resource/AuthenticationSSOSucceededContextActor.php create mode 100644 lib/Resource/AuthenticationSSOSucceededContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/AuthenticationSSOSucceededData.php create mode 100644 lib/Resource/AuthenticationSSOSucceededDataSSO.php create mode 100644 lib/Resource/AuthenticationSSOTimedOut.php create mode 100644 lib/Resource/AuthenticationSSOTimedOutContext.php create mode 100644 lib/Resource/AuthenticationSSOTimedOutContextActor.php create mode 100644 lib/Resource/AuthenticationSSOTimedOutContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/AuthenticationSSOTimedOutData.php create mode 100644 lib/Resource/AuthenticationSSOTimedOutDataError.php create mode 100644 lib/Resource/AuthenticationSSOTimedOutDataSSO.php create mode 100644 lib/Resource/AuthorizationAssignment.php create mode 100644 lib/Resource/AuthorizationCheck.php create mode 100644 lib/Resource/AuthorizationCodeSessionAuthenticateRequest.php create mode 100644 lib/Resource/AuthorizationOrder.php create mode 100644 lib/Resource/AuthorizationPermission.php create mode 100644 lib/Resource/AuthorizationResource.php create mode 100644 lib/Resource/AuthorizedConnectApplicationListData.php delete mode 100644 lib/Resource/BaseWorkOSResource.php create mode 100644 lib/Resource/CORSOriginResponse.php create mode 100644 lib/Resource/ChallengeAuthenticationFactor.php create mode 100644 lib/Resource/CheckAuthorization.php create mode 100644 lib/Resource/ConfirmEmailChange.php create mode 100644 lib/Resource/ConnectApplication.php create mode 100644 lib/Resource/ConnectedAccount.php create mode 100644 lib/Resource/ConnectedAccountState.php create mode 100644 lib/Resource/ConnectionActivated.php create mode 100644 lib/Resource/ConnectionActivatedContext.php create mode 100644 lib/Resource/ConnectionActivatedContextActor.php create mode 100644 lib/Resource/ConnectionActivatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/ConnectionActivatedData.php create mode 100644 lib/Resource/ConnectionActivatedDataDomain.php create mode 100644 lib/Resource/ConnectionDeactivated.php create mode 100644 lib/Resource/ConnectionDeactivatedContext.php create mode 100644 lib/Resource/ConnectionDeactivatedContextActor.php create mode 100644 lib/Resource/ConnectionDeactivatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/ConnectionDeactivatedData.php create mode 100644 lib/Resource/ConnectionDeactivatedDataDomain.php create mode 100644 lib/Resource/ConnectionDeleted.php create mode 100644 lib/Resource/ConnectionDeletedContext.php create mode 100644 lib/Resource/ConnectionDeletedContextActor.php create mode 100644 lib/Resource/ConnectionDeletedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/ConnectionDeletedData.php create mode 100644 lib/Resource/ConnectionDeletedDataConnectionType.php create mode 100644 lib/Resource/ConnectionDeletedDataState.php create mode 100644 lib/Resource/ConnectionDomain.php create mode 100644 lib/Resource/ConnectionOption.php create mode 100644 lib/Resource/ConnectionSAMLCertificateRenewalRequired.php create mode 100644 lib/Resource/ConnectionSAMLCertificateRenewalRequiredContext.php create mode 100644 lib/Resource/ConnectionSAMLCertificateRenewalRequiredContextActor.php create mode 100644 lib/Resource/ConnectionSAMLCertificateRenewalRequiredContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/ConnectionSAMLCertificateRenewalRequiredData.php create mode 100644 lib/Resource/ConnectionSAMLCertificateRenewalRequiredDataCertificate.php create mode 100644 lib/Resource/ConnectionSAMLCertificateRenewalRequiredDataConnection.php create mode 100644 lib/Resource/ConnectionSAMLCertificateRenewed.php create mode 100644 lib/Resource/ConnectionSAMLCertificateRenewedContext.php create mode 100644 lib/Resource/ConnectionSAMLCertificateRenewedContextActor.php create mode 100644 lib/Resource/ConnectionSAMLCertificateRenewedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/ConnectionSAMLCertificateRenewedData.php create mode 100644 lib/Resource/ConnectionSAMLCertificateRenewedDataCertificate.php create mode 100644 lib/Resource/ConnectionSAMLCertificateRenewedDataCertificateCertificateType.php create mode 100644 lib/Resource/ConnectionSAMLCertificateRenewedDataConnection.php create mode 100644 lib/Resource/ConnectionState.php create mode 100644 lib/Resource/ConnectionStatus.php create mode 100644 lib/Resource/ConnectionsConnectionType.php create mode 100644 lib/Resource/ConnectionsOrder.php create mode 100644 lib/Resource/CreateApplicationSecret.php create mode 100644 lib/Resource/CreateAuthorizationPermission.php create mode 100644 lib/Resource/CreateAuthorizationResource.php create mode 100644 lib/Resource/CreateCORSOrigin.php create mode 100644 lib/Resource/CreateM2MApplication.php create mode 100644 lib/Resource/CreateMagicCodeAndReturn.php create mode 100644 lib/Resource/CreateOAuthApplication.php create mode 100644 lib/Resource/CreateOrganizationApiKey.php create mode 100644 lib/Resource/CreateOrganizationDomain.php create mode 100644 lib/Resource/CreateOrganizationRole.php create mode 100644 lib/Resource/CreatePasswordReset.php create mode 100644 lib/Resource/CreatePasswordResetToken.php create mode 100644 lib/Resource/CreateRedirectUri.php create mode 100644 lib/Resource/CreateRole.php create mode 100644 lib/Resource/CreateUser.php create mode 100644 lib/Resource/CreateUserInviteOptions.php create mode 100644 lib/Resource/CreateUserInviteOptionsLocale.php create mode 100644 lib/Resource/CreateUserOrganizationMembership.php create mode 100644 lib/Resource/CreateUserPasswordHashType.php create mode 100644 lib/Resource/CreateWebhookEndpoint.php create mode 100644 lib/Resource/CreateWebhookEndpointEvents.php create mode 100644 lib/Resource/DataIntegrationAccessTokenResponse.php create mode 100644 lib/Resource/DataIntegrationAuthorizeUrlResponse.php create mode 100644 lib/Resource/DataIntegrationsGetDataIntegrationAuthorizeUrlRequest.php create mode 100644 lib/Resource/DataIntegrationsGetUserTokenRequest.php create mode 100644 lib/Resource/DataIntegrationsListResponse.php create mode 100644 lib/Resource/DataIntegrationsListResponseData.php create mode 100644 lib/Resource/DataIntegrationsListResponseDataConnectedAccount.php create mode 100644 lib/Resource/DataIntegrationsListResponseDataConnectedAccountState.php create mode 100644 lib/Resource/DataIntegrationsListResponseDataOwnership.php create mode 100644 lib/Resource/DeviceAuthorizationResponse.php create mode 100644 lib/Resource/DeviceCodeSessionAuthenticateRequest.php create mode 100644 lib/Resource/DirectoriesOrder.php create mode 100644 lib/Resource/DirectoryGroupsOrder.php create mode 100644 lib/Resource/DirectoryMetadata.php create mode 100644 lib/Resource/DirectoryMetadataUser.php create mode 100644 lib/Resource/DirectoryState.php create mode 100644 lib/Resource/DirectoryType.php create mode 100644 lib/Resource/DirectoryUserEmail.php create mode 100644 lib/Resource/DirectoryUserState.php create mode 100644 lib/Resource/DirectoryUserWithGroups.php create mode 100644 lib/Resource/DirectoryUserWithGroupsEmail.php create mode 100644 lib/Resource/DirectoryUserWithGroupsState.php create mode 100644 lib/Resource/DirectoryUsersOrder.php delete mode 100644 lib/Resource/Domain.php create mode 100644 lib/Resource/DsyncActivated.php create mode 100644 lib/Resource/DsyncActivatedContext.php create mode 100644 lib/Resource/DsyncActivatedContextActor.php create mode 100644 lib/Resource/DsyncActivatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/DsyncActivatedData.php create mode 100644 lib/Resource/DsyncActivatedDataDomain.php create mode 100644 lib/Resource/DsyncDeactivated.php create mode 100644 lib/Resource/DsyncDeactivatedContext.php create mode 100644 lib/Resource/DsyncDeactivatedContextActor.php create mode 100644 lib/Resource/DsyncDeactivatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/DsyncDeactivatedData.php create mode 100644 lib/Resource/DsyncDeactivatedDataDomain.php create mode 100644 lib/Resource/DsyncDeleted.php create mode 100644 lib/Resource/DsyncDeletedContext.php create mode 100644 lib/Resource/DsyncDeletedContextActor.php create mode 100644 lib/Resource/DsyncDeletedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/DsyncDeletedData.php create mode 100644 lib/Resource/DsyncDeletedDataState.php create mode 100644 lib/Resource/DsyncDeletedDataType.php create mode 100644 lib/Resource/DsyncGroupCreated.php create mode 100644 lib/Resource/DsyncGroupCreatedContext.php create mode 100644 lib/Resource/DsyncGroupCreatedContextActor.php create mode 100644 lib/Resource/DsyncGroupCreatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/DsyncGroupCreatedData.php create mode 100644 lib/Resource/DsyncGroupDeleted.php create mode 100644 lib/Resource/DsyncGroupDeletedContext.php create mode 100644 lib/Resource/DsyncGroupDeletedContextActor.php create mode 100644 lib/Resource/DsyncGroupDeletedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/DsyncGroupDeletedData.php create mode 100644 lib/Resource/DsyncGroupUpdated.php create mode 100644 lib/Resource/DsyncGroupUpdatedContext.php create mode 100644 lib/Resource/DsyncGroupUpdatedContextActor.php create mode 100644 lib/Resource/DsyncGroupUpdatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/DsyncGroupUpdatedData.php create mode 100644 lib/Resource/DsyncGroupUserAdded.php create mode 100644 lib/Resource/DsyncGroupUserAddedContext.php create mode 100644 lib/Resource/DsyncGroupUserAddedContextActor.php create mode 100644 lib/Resource/DsyncGroupUserAddedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/DsyncGroupUserAddedData.php create mode 100644 lib/Resource/DsyncGroupUserAddedDataGroup.php create mode 100644 lib/Resource/DsyncGroupUserAddedDataUser.php create mode 100644 lib/Resource/DsyncGroupUserAddedDataUserEmail.php create mode 100644 lib/Resource/DsyncGroupUserAddedDataUserRole.php create mode 100644 lib/Resource/DsyncGroupUserRemoved.php create mode 100644 lib/Resource/DsyncGroupUserRemovedContext.php create mode 100644 lib/Resource/DsyncGroupUserRemovedContextActor.php create mode 100644 lib/Resource/DsyncGroupUserRemovedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/DsyncGroupUserRemovedData.php create mode 100644 lib/Resource/DsyncGroupUserRemovedDataGroup.php create mode 100644 lib/Resource/DsyncGroupUserRemovedDataUser.php create mode 100644 lib/Resource/DsyncGroupUserRemovedDataUserEmail.php create mode 100644 lib/Resource/DsyncGroupUserRemovedDataUserRole.php create mode 100644 lib/Resource/DsyncUserCreated.php create mode 100644 lib/Resource/DsyncUserCreatedContext.php create mode 100644 lib/Resource/DsyncUserCreatedContextActor.php create mode 100644 lib/Resource/DsyncUserCreatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/DsyncUserCreatedData.php create mode 100644 lib/Resource/DsyncUserCreatedDataEmail.php create mode 100644 lib/Resource/DsyncUserCreatedDataRole.php create mode 100644 lib/Resource/DsyncUserCreatedDataState.php create mode 100644 lib/Resource/DsyncUserDeleted.php create mode 100644 lib/Resource/DsyncUserDeletedContext.php create mode 100644 lib/Resource/DsyncUserDeletedContextActor.php create mode 100644 lib/Resource/DsyncUserDeletedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/DsyncUserDeletedData.php create mode 100644 lib/Resource/DsyncUserDeletedDataEmail.php create mode 100644 lib/Resource/DsyncUserDeletedDataRole.php create mode 100644 lib/Resource/DsyncUserUpdated.php create mode 100644 lib/Resource/DsyncUserUpdatedContext.php create mode 100644 lib/Resource/DsyncUserUpdatedContextActor.php create mode 100644 lib/Resource/DsyncUserUpdatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/DsyncUserUpdatedData.php create mode 100644 lib/Resource/DsyncUserUpdatedDataEmail.php create mode 100644 lib/Resource/DsyncUserUpdatedDataRole.php create mode 100644 lib/Resource/EmailChange.php create mode 100644 lib/Resource/EmailChangeConfirmation.php create mode 100644 lib/Resource/EmailChangeConfirmationUser.php create mode 100644 lib/Resource/EmailVerificationCodeSessionAuthenticateRequest.php create mode 100644 lib/Resource/EmailVerificationCreated.php create mode 100644 lib/Resource/EmailVerificationCreatedContext.php create mode 100644 lib/Resource/EmailVerificationCreatedContextActor.php create mode 100644 lib/Resource/EmailVerificationCreatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/EmailVerificationCreatedData.php create mode 100644 lib/Resource/EnrollUserAuthenticationFactor.php create mode 100644 lib/Resource/EventContext.php create mode 100644 lib/Resource/EventContextActor.php create mode 100644 lib/Resource/EventContextActorSource.php create mode 100644 lib/Resource/EventContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/EventListListMetadata.php create mode 100644 lib/Resource/EventSchema.php create mode 100644 lib/Resource/EventsOrder.php create mode 100644 lib/Resource/ExternalAuthCompleteResponse.php create mode 100644 lib/Resource/FeatureFlagOwner.php create mode 100644 lib/Resource/FeatureFlagsOrder.php create mode 100644 lib/Resource/Flag.php create mode 100644 lib/Resource/FlagCreated.php create mode 100644 lib/Resource/FlagCreatedContext.php create mode 100644 lib/Resource/FlagCreatedContextActor.php create mode 100644 lib/Resource/FlagCreatedContextActorSource.php create mode 100644 lib/Resource/FlagCreatedData.php create mode 100644 lib/Resource/FlagCreatedDataOwner.php create mode 100644 lib/Resource/FlagDeleted.php create mode 100644 lib/Resource/FlagDeletedContext.php create mode 100644 lib/Resource/FlagDeletedContextActor.php create mode 100644 lib/Resource/FlagDeletedData.php create mode 100644 lib/Resource/FlagDeletedDataOwner.php create mode 100644 lib/Resource/FlagOwner.php create mode 100644 lib/Resource/FlagRuleUpdated.php create mode 100644 lib/Resource/FlagRuleUpdatedContext.php create mode 100644 lib/Resource/FlagRuleUpdatedContextAccessType.php create mode 100644 lib/Resource/FlagRuleUpdatedContextActor.php create mode 100644 lib/Resource/FlagRuleUpdatedContextConfiguredTarget.php create mode 100644 lib/Resource/FlagRuleUpdatedContextConfiguredTargetOrganization.php create mode 100644 lib/Resource/FlagRuleUpdatedContextConfiguredTargetUser.php create mode 100644 lib/Resource/FlagRuleUpdatedContextPreviousAttribute.php create mode 100644 lib/Resource/FlagRuleUpdatedContextPreviousAttributeContext.php create mode 100644 lib/Resource/FlagRuleUpdatedContextPreviousAttributeContextConfiguredTarget.php create mode 100644 lib/Resource/FlagRuleUpdatedContextPreviousAttributeContextConfiguredTargetOrganization.php create mode 100644 lib/Resource/FlagRuleUpdatedContextPreviousAttributeContextConfiguredTargetUser.php create mode 100644 lib/Resource/FlagRuleUpdatedContextPreviousAttributeData.php create mode 100644 lib/Resource/FlagRuleUpdatedData.php create mode 100644 lib/Resource/FlagRuleUpdatedDataOwner.php create mode 100644 lib/Resource/FlagUpdated.php create mode 100644 lib/Resource/FlagUpdatedContext.php create mode 100644 lib/Resource/FlagUpdatedContextActor.php create mode 100644 lib/Resource/FlagUpdatedContextPreviousAttribute.php create mode 100644 lib/Resource/FlagUpdatedContextPreviousAttributeData.php create mode 100644 lib/Resource/FlagUpdatedData.php create mode 100644 lib/Resource/FlagUpdatedDataOwner.php create mode 100644 lib/Resource/GenerateLink.php create mode 100644 lib/Resource/GenerateLinkIntent.php delete mode 100644 lib/Resource/Impersonator.php create mode 100644 lib/Resource/IntentOptions.php create mode 100644 lib/Resource/InvitationAccepted.php create mode 100644 lib/Resource/InvitationAcceptedContext.php create mode 100644 lib/Resource/InvitationAcceptedContextActor.php create mode 100644 lib/Resource/InvitationAcceptedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/InvitationAcceptedData.php create mode 100644 lib/Resource/InvitationCreated.php create mode 100644 lib/Resource/InvitationCreatedContext.php create mode 100644 lib/Resource/InvitationCreatedContextActor.php create mode 100644 lib/Resource/InvitationCreatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/InvitationCreatedData.php create mode 100644 lib/Resource/InvitationResent.php create mode 100644 lib/Resource/InvitationResentContext.php create mode 100644 lib/Resource/InvitationResentContextActor.php create mode 100644 lib/Resource/InvitationResentContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/InvitationResentData.php create mode 100644 lib/Resource/InvitationRevoked.php create mode 100644 lib/Resource/InvitationRevokedContext.php create mode 100644 lib/Resource/InvitationRevokedContextActor.php create mode 100644 lib/Resource/InvitationRevokedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/InvitationRevokedData.php create mode 100644 lib/Resource/InvitationState.php create mode 100644 lib/Resource/JWTTemplateResponse.php create mode 100644 lib/Resource/JsonSerializableTrait.php create mode 100644 lib/Resource/JwksResponse.php create mode 100644 lib/Resource/JwksResponseKeys.php create mode 100644 lib/Resource/ListData.php create mode 100644 lib/Resource/ListDataType.php create mode 100644 lib/Resource/ListModel.php create mode 100644 lib/Resource/MFATotpSessionAuthenticateRequest.php create mode 100644 lib/Resource/MagicAuthCodeSessionAuthenticateRequest.php create mode 100644 lib/Resource/MagicAuthCreated.php create mode 100644 lib/Resource/MagicAuthCreatedContext.php create mode 100644 lib/Resource/MagicAuthCreatedContextActor.php create mode 100644 lib/Resource/MagicAuthCreatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/MagicAuthCreatedData.php create mode 100644 lib/Resource/NewConnectApplicationSecret.php delete mode 100644 lib/Resource/OAuthTokens.php delete mode 100644 lib/Resource/Order.php create mode 100644 lib/Resource/OrganizationCreated.php create mode 100644 lib/Resource/OrganizationCreatedContext.php create mode 100644 lib/Resource/OrganizationCreatedContextActor.php create mode 100644 lib/Resource/OrganizationCreatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/OrganizationCreatedData.php create mode 100644 lib/Resource/OrganizationCreatedDataDomain.php create mode 100644 lib/Resource/OrganizationDeleted.php create mode 100644 lib/Resource/OrganizationDeletedContext.php create mode 100644 lib/Resource/OrganizationDeletedContextActor.php create mode 100644 lib/Resource/OrganizationDeletedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/OrganizationDeletedData.php create mode 100644 lib/Resource/OrganizationDeletedDataDomain.php create mode 100644 lib/Resource/OrganizationDomain.php create mode 100644 lib/Resource/OrganizationDomainCreated.php create mode 100644 lib/Resource/OrganizationDomainCreatedContext.php create mode 100644 lib/Resource/OrganizationDomainCreatedContextActor.php create mode 100644 lib/Resource/OrganizationDomainCreatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/OrganizationDomainCreatedData.php create mode 100644 lib/Resource/OrganizationDomainData.php create mode 100644 lib/Resource/OrganizationDomainDataState.php create mode 100644 lib/Resource/OrganizationDomainDeleted.php create mode 100644 lib/Resource/OrganizationDomainDeletedContext.php create mode 100644 lib/Resource/OrganizationDomainDeletedContextActor.php create mode 100644 lib/Resource/OrganizationDomainDeletedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/OrganizationDomainDeletedData.php create mode 100644 lib/Resource/OrganizationDomainStandAlone.php create mode 100644 lib/Resource/OrganizationDomainStandAloneState.php create mode 100644 lib/Resource/OrganizationDomainStandAloneVerificationStrategy.php create mode 100644 lib/Resource/OrganizationDomainState.php create mode 100644 lib/Resource/OrganizationDomainUpdated.php create mode 100644 lib/Resource/OrganizationDomainUpdatedContext.php create mode 100644 lib/Resource/OrganizationDomainUpdatedContextActor.php create mode 100644 lib/Resource/OrganizationDomainUpdatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/OrganizationDomainUpdatedData.php create mode 100644 lib/Resource/OrganizationDomainVerificationFailed.php create mode 100644 lib/Resource/OrganizationDomainVerificationFailedContext.php create mode 100644 lib/Resource/OrganizationDomainVerificationFailedContextActor.php create mode 100644 lib/Resource/OrganizationDomainVerificationFailedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/OrganizationDomainVerificationFailedData.php create mode 100644 lib/Resource/OrganizationDomainVerificationFailedDataOrganizationDomain.php create mode 100644 lib/Resource/OrganizationDomainVerificationFailedDataReason.php create mode 100644 lib/Resource/OrganizationDomainVerificationStrategy.php create mode 100644 lib/Resource/OrganizationDomainVerified.php create mode 100644 lib/Resource/OrganizationDomainVerifiedContext.php create mode 100644 lib/Resource/OrganizationDomainVerifiedContextActor.php create mode 100644 lib/Resource/OrganizationDomainVerifiedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/OrganizationDomainVerifiedData.php create mode 100644 lib/Resource/OrganizationInput.php create mode 100644 lib/Resource/OrganizationMembershipCreated.php create mode 100644 lib/Resource/OrganizationMembershipCreatedContext.php create mode 100644 lib/Resource/OrganizationMembershipCreatedContextActor.php create mode 100644 lib/Resource/OrganizationMembershipCreatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/OrganizationMembershipCreatedData.php create mode 100644 lib/Resource/OrganizationMembershipDeleted.php create mode 100644 lib/Resource/OrganizationMembershipDeletedContext.php create mode 100644 lib/Resource/OrganizationMembershipDeletedContextActor.php create mode 100644 lib/Resource/OrganizationMembershipDeletedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/OrganizationMembershipDeletedData.php create mode 100644 lib/Resource/OrganizationMembershipStatus.php create mode 100644 lib/Resource/OrganizationMembershipUpdated.php create mode 100644 lib/Resource/OrganizationMembershipUpdatedContext.php create mode 100644 lib/Resource/OrganizationMembershipUpdatedContextActor.php create mode 100644 lib/Resource/OrganizationMembershipUpdatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/OrganizationMembershipUpdatedData.php create mode 100644 lib/Resource/OrganizationRoleCreated.php create mode 100644 lib/Resource/OrganizationRoleCreatedContext.php create mode 100644 lib/Resource/OrganizationRoleCreatedContextActor.php create mode 100644 lib/Resource/OrganizationRoleCreatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/OrganizationRoleCreatedData.php create mode 100644 lib/Resource/OrganizationRoleDeleted.php create mode 100644 lib/Resource/OrganizationRoleDeletedContext.php create mode 100644 lib/Resource/OrganizationRoleDeletedContextActor.php create mode 100644 lib/Resource/OrganizationRoleDeletedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/OrganizationRoleDeletedData.php create mode 100644 lib/Resource/OrganizationRoleUpdated.php create mode 100644 lib/Resource/OrganizationRoleUpdatedContext.php create mode 100644 lib/Resource/OrganizationRoleUpdatedContextActor.php create mode 100644 lib/Resource/OrganizationRoleUpdatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/OrganizationRoleUpdatedData.php create mode 100644 lib/Resource/OrganizationSelectionSessionAuthenticateRequest.php create mode 100644 lib/Resource/OrganizationUpdated.php create mode 100644 lib/Resource/OrganizationUpdatedContext.php create mode 100644 lib/Resource/OrganizationUpdatedContextActor.php create mode 100644 lib/Resource/OrganizationUpdatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/OrganizationUpdatedData.php create mode 100644 lib/Resource/OrganizationUpdatedDataDomain.php create mode 100644 lib/Resource/OrganizationsApiKeysOrder.php create mode 100644 lib/Resource/OrganizationsFeatureFlagsOrder.php create mode 100644 lib/Resource/OrganizationsOrder.php delete mode 100644 lib/Resource/PaginatedResource.php create mode 100644 lib/Resource/PasswordResetCreated.php create mode 100644 lib/Resource/PasswordResetCreatedContext.php create mode 100644 lib/Resource/PasswordResetCreatedContextActor.php create mode 100644 lib/Resource/PasswordResetCreatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/PasswordResetCreatedData.php create mode 100644 lib/Resource/PasswordResetSucceeded.php create mode 100644 lib/Resource/PasswordResetSucceededContext.php create mode 100644 lib/Resource/PasswordResetSucceededContextActor.php create mode 100644 lib/Resource/PasswordResetSucceededContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/PasswordResetSucceededData.php create mode 100644 lib/Resource/PasswordSessionAuthenticateRequest.php delete mode 100644 lib/Resource/PasswordlessSession.php create mode 100644 lib/Resource/PermissionCreated.php create mode 100644 lib/Resource/PermissionCreatedContext.php create mode 100644 lib/Resource/PermissionCreatedContextActor.php create mode 100644 lib/Resource/PermissionCreatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/PermissionCreatedData.php create mode 100644 lib/Resource/PermissionDeleted.php create mode 100644 lib/Resource/PermissionDeletedContext.php create mode 100644 lib/Resource/PermissionDeletedContextActor.php create mode 100644 lib/Resource/PermissionDeletedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/PermissionDeletedData.php create mode 100644 lib/Resource/PermissionUpdated.php create mode 100644 lib/Resource/PermissionUpdatedContext.php create mode 100644 lib/Resource/PermissionUpdatedContextActor.php create mode 100644 lib/Resource/PermissionUpdatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/PermissionUpdatedData.php create mode 100644 lib/Resource/PermissionsOrder.php delete mode 100644 lib/Resource/PortalLink.php create mode 100644 lib/Resource/PortalLinkResponse.php delete mode 100644 lib/Resource/ProfileAndToken.php create mode 100644 lib/Resource/ProfileConnectionType.php create mode 100644 lib/Resource/RadarAction.php create mode 100644 lib/Resource/RadarListEntryAlreadyPresentResponse.php create mode 100644 lib/Resource/RadarStandaloneAssessRequest.php create mode 100644 lib/Resource/RadarStandaloneAssessRequestAction.php create mode 100644 lib/Resource/RadarStandaloneAssessRequestAuthMethod.php create mode 100644 lib/Resource/RadarStandaloneDeleteRadarListEntryRequest.php create mode 100644 lib/Resource/RadarStandaloneResponse.php create mode 100644 lib/Resource/RadarStandaloneResponseBlocklistType.php create mode 100644 lib/Resource/RadarStandaloneResponseControl.php create mode 100644 lib/Resource/RadarStandaloneResponseVerdict.php create mode 100644 lib/Resource/RadarStandaloneUpdateRadarAttemptRequest.php create mode 100644 lib/Resource/RadarStandaloneUpdateRadarListRequest.php create mode 100644 lib/Resource/RadarType.php create mode 100644 lib/Resource/RedirectUri.php create mode 100644 lib/Resource/RedirectUriInput.php create mode 100644 lib/Resource/RefreshTokenSessionAuthenticateRequest.php create mode 100644 lib/Resource/RemoveRole.php create mode 100644 lib/Resource/ResendUserInviteOptions.php create mode 100644 lib/Resource/ResendUserInviteOptionsLocale.php create mode 100644 lib/Resource/ResetPasswordResponse.php delete mode 100644 lib/Resource/Response.php create mode 100644 lib/Resource/RevokeSession.php create mode 100644 lib/Resource/RoleAssignment.php create mode 100644 lib/Resource/RoleAssignmentResource.php create mode 100644 lib/Resource/RoleCreated.php create mode 100644 lib/Resource/RoleCreatedContext.php create mode 100644 lib/Resource/RoleCreatedContextActor.php create mode 100644 lib/Resource/RoleCreatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/RoleCreatedData.php create mode 100644 lib/Resource/RoleDeleted.php create mode 100644 lib/Resource/RoleDeletedContext.php create mode 100644 lib/Resource/RoleDeletedContextActor.php create mode 100644 lib/Resource/RoleDeletedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/RoleDeletedData.php create mode 100644 lib/Resource/RoleList.php delete mode 100644 lib/Resource/RoleResponse.php create mode 100644 lib/Resource/RoleType.php create mode 100644 lib/Resource/RoleUpdated.php create mode 100644 lib/Resource/RoleUpdatedContext.php create mode 100644 lib/Resource/RoleUpdatedContextActor.php create mode 100644 lib/Resource/RoleUpdatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/RoleUpdatedData.php create mode 100644 lib/Resource/SSOAuthorizeUrlResponse.php create mode 100644 lib/Resource/SSODeviceAuthorizationRequest.php create mode 100644 lib/Resource/SSOIntentOptions.php create mode 100644 lib/Resource/SSOLogoutAuthorizeRequest.php create mode 100644 lib/Resource/SSOLogoutAuthorizeResponse.php create mode 100644 lib/Resource/SSOProvider.php create mode 100644 lib/Resource/SSOTokenResponse.php create mode 100644 lib/Resource/SSOTokenResponseOAuthToken.php create mode 100644 lib/Resource/SendEmailChange.php create mode 100644 lib/Resource/SendVerificationEmailResponse.php delete mode 100644 lib/Resource/Session.php delete mode 100644 lib/Resource/SessionAuthenticationFailureResponse.php delete mode 100644 lib/Resource/SessionAuthenticationSuccessResponse.php create mode 100644 lib/Resource/SessionCreated.php create mode 100644 lib/Resource/SessionCreatedContext.php create mode 100644 lib/Resource/SessionCreatedContextActor.php create mode 100644 lib/Resource/SessionCreatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/SessionCreatedData.php create mode 100644 lib/Resource/SessionCreatedDataImpersonator.php create mode 100644 lib/Resource/SessionRevoked.php create mode 100644 lib/Resource/SessionRevokedContext.php create mode 100644 lib/Resource/SessionRevokedContextActor.php create mode 100644 lib/Resource/SessionRevokedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/SessionRevokedData.php create mode 100644 lib/Resource/SessionRevokedDataImpersonator.php create mode 100644 lib/Resource/SetRolePermissions.php create mode 100644 lib/Resource/SlimRole.php create mode 100644 lib/Resource/TokenQuery.php create mode 100644 lib/Resource/UpdateAuditLogsRetention.php create mode 100644 lib/Resource/UpdateAuthorizationPermission.php create mode 100644 lib/Resource/UpdateAuthorizationResource.php create mode 100644 lib/Resource/UpdateJWTTemplate.php create mode 100644 lib/Resource/UpdateOAuthApplication.php create mode 100644 lib/Resource/UpdateOrganization.php create mode 100644 lib/Resource/UpdateOrganizationRole.php create mode 100644 lib/Resource/UpdateRole.php create mode 100644 lib/Resource/UpdateUser.php create mode 100644 lib/Resource/UpdateUserOrganizationMembership.php create mode 100644 lib/Resource/UpdateUserPasswordHashType.php create mode 100644 lib/Resource/UpdateWebhookEndpoint.php create mode 100644 lib/Resource/UpdateWebhookEndpointEvents.php create mode 100644 lib/Resource/UpdateWebhookEndpointStatus.php delete mode 100644 lib/Resource/UserAndToken.php create mode 100644 lib/Resource/UserAuthenticationFactorEnrollResponse.php delete mode 100644 lib/Resource/UserAuthenticationFactorTotp.php create mode 100644 lib/Resource/UserConsentOption.php create mode 100644 lib/Resource/UserConsentOptionChoice.php create mode 100644 lib/Resource/UserCreated.php create mode 100644 lib/Resource/UserCreatedContext.php create mode 100644 lib/Resource/UserCreatedContextActor.php create mode 100644 lib/Resource/UserCreatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/UserCreatedData.php create mode 100644 lib/Resource/UserDeleted.php create mode 100644 lib/Resource/UserDeletedContext.php create mode 100644 lib/Resource/UserDeletedContextActor.php create mode 100644 lib/Resource/UserDeletedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/UserDeletedData.php create mode 100644 lib/Resource/UserIdentitiesGetItem.php create mode 100644 lib/Resource/UserIdentitiesGetItemProvider.php create mode 100644 lib/Resource/UserInvite.php create mode 100644 lib/Resource/UserInviteState.php create mode 100644 lib/Resource/UserManagementAuthenticationProvider.php create mode 100644 lib/Resource/UserManagementAuthenticationScreenHint.php create mode 100644 lib/Resource/UserManagementInvitationsOrder.php create mode 100644 lib/Resource/UserManagementLoginRequest.php create mode 100644 lib/Resource/UserManagementMultiFactorAuthenticationOrder.php create mode 100644 lib/Resource/UserManagementOrganizationMembershipOrder.php create mode 100644 lib/Resource/UserManagementOrganizationMembershipStatuses.php create mode 100644 lib/Resource/UserManagementUsersAuthorizedApplicationsOrder.php create mode 100644 lib/Resource/UserManagementUsersFeatureFlagsOrder.php create mode 100644 lib/Resource/UserManagementUsersOrder.php create mode 100644 lib/Resource/UserObject.php create mode 100644 lib/Resource/UserOrganizationMembership.php create mode 100644 lib/Resource/UserOrganizationMembershipBaseListData.php create mode 100644 lib/Resource/UserOrganizationMembershipBaseListDataStatus.php create mode 100644 lib/Resource/UserOrganizationMembershipStatus.php delete mode 100644 lib/Resource/UserResponse.php create mode 100644 lib/Resource/UserSessionsAuthMethod.php create mode 100644 lib/Resource/UserSessionsImpersonator.php create mode 100644 lib/Resource/UserSessionsListItem.php create mode 100644 lib/Resource/UserSessionsStatus.php create mode 100644 lib/Resource/UserUpdated.php create mode 100644 lib/Resource/UserUpdatedContext.php create mode 100644 lib/Resource/UserUpdatedContextActor.php create mode 100644 lib/Resource/UserUpdatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/UserUpdatedData.php create mode 100644 lib/Resource/ValidateApiKey.php create mode 100644 lib/Resource/VaultByokKeyVerificationCompleted.php create mode 100644 lib/Resource/VaultByokKeyVerificationCompletedContext.php create mode 100644 lib/Resource/VaultByokKeyVerificationCompletedContextActor.php create mode 100644 lib/Resource/VaultByokKeyVerificationCompletedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/VaultByokKeyVerificationCompletedData.php create mode 100644 lib/Resource/VaultByokKeyVerificationCompletedDataKeyProvider.php create mode 100644 lib/Resource/VaultDataCreated.php create mode 100644 lib/Resource/VaultDataCreatedContext.php create mode 100644 lib/Resource/VaultDataCreatedContextActor.php create mode 100644 lib/Resource/VaultDataCreatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/VaultDataCreatedData.php create mode 100644 lib/Resource/VaultDataDeleted.php create mode 100644 lib/Resource/VaultDataDeletedContext.php create mode 100644 lib/Resource/VaultDataDeletedContextActor.php create mode 100644 lib/Resource/VaultDataDeletedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/VaultDataDeletedData.php create mode 100644 lib/Resource/VaultDataRead.php create mode 100644 lib/Resource/VaultDataReadContext.php create mode 100644 lib/Resource/VaultDataReadContextActor.php create mode 100644 lib/Resource/VaultDataReadContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/VaultDataReadData.php create mode 100644 lib/Resource/VaultDataUpdated.php create mode 100644 lib/Resource/VaultDataUpdatedContext.php create mode 100644 lib/Resource/VaultDataUpdatedContextActor.php create mode 100644 lib/Resource/VaultDataUpdatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/VaultDataUpdatedData.php create mode 100644 lib/Resource/VaultDekDecrypted.php create mode 100644 lib/Resource/VaultDekDecryptedContext.php create mode 100644 lib/Resource/VaultDekDecryptedContextActor.php create mode 100644 lib/Resource/VaultDekDecryptedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/VaultDekDecryptedData.php create mode 100644 lib/Resource/VaultDekRead.php create mode 100644 lib/Resource/VaultDekReadContext.php create mode 100644 lib/Resource/VaultDekReadContextActor.php create mode 100644 lib/Resource/VaultDekReadContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/VaultDekReadData.php create mode 100644 lib/Resource/VaultDekReadDataActorSource.php create mode 100644 lib/Resource/VaultKekCreated.php create mode 100644 lib/Resource/VaultKekCreatedContext.php create mode 100644 lib/Resource/VaultKekCreatedContextActor.php create mode 100644 lib/Resource/VaultKekCreatedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/VaultKekCreatedData.php create mode 100644 lib/Resource/VaultMetadataRead.php create mode 100644 lib/Resource/VaultMetadataReadContext.php create mode 100644 lib/Resource/VaultMetadataReadContextActor.php create mode 100644 lib/Resource/VaultMetadataReadContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/VaultMetadataReadData.php create mode 100644 lib/Resource/VaultNamesListed.php create mode 100644 lib/Resource/VaultNamesListedContext.php create mode 100644 lib/Resource/VaultNamesListedContextActor.php create mode 100644 lib/Resource/VaultNamesListedContextGoogleAnalyticsSession.php create mode 100644 lib/Resource/VaultNamesListedData.php delete mode 100644 lib/Resource/VaultObject.php delete mode 100644 lib/Resource/VerificationChallenge.php create mode 100644 lib/Resource/VerifyEmailAddress.php create mode 100644 lib/Resource/VerifyEmailResponse.php create mode 100644 lib/Resource/WebhookEndpointJson.php create mode 100644 lib/Resource/WebhookEndpointJsonStatus.php create mode 100644 lib/Resource/WebhooksOrder.php delete mode 100644 lib/Resource/WidgetScope.php create mode 100644 lib/Resource/WidgetSessionToken.php create mode 100644 lib/Resource/WidgetSessionTokenResponse.php create mode 100644 lib/Resource/WidgetSessionTokenScopes.php delete mode 100644 lib/Resource/WidgetTokenResponse.php delete mode 100644 lib/SSO.php create mode 100644 lib/Service/AdminPortal.php create mode 100644 lib/Service/ApiKeys.php create mode 100644 lib/Service/AuditLogs.php create mode 100644 lib/Service/Authorization.php create mode 100644 lib/Service/Connect.php create mode 100644 lib/Service/DirectorySync.php create mode 100644 lib/Service/Events.php create mode 100644 lib/Service/FeatureFlags.php create mode 100644 lib/Service/MultiFactorAuth.php create mode 100644 lib/Service/OrganizationDomains.php create mode 100644 lib/Service/Organizations.php create mode 100644 lib/Service/Pipes.php create mode 100644 lib/Service/Radar.php create mode 100644 lib/Service/SSO.php create mode 100644 lib/Service/UserManagement.php create mode 100644 lib/Service/Webhooks.php create mode 100644 lib/Service/Widgets.php delete mode 100644 lib/Session/HaliteSessionEncryption.php delete mode 100644 lib/Session/SessionEncryptionInterface.php delete mode 100644 lib/Session/SigningOnlySessionHandler.php create mode 100644 lib/SessionManager.php delete mode 100644 lib/UserManagement.php delete mode 100644 lib/Util/Request.php delete mode 100644 lib/Webhook.php create mode 100644 lib/WebhookVerification.php delete mode 100644 lib/Widgets.php create mode 100644 phpstan.neon create mode 100755 script/ci create mode 100644 tests/ActionsTest.php create mode 100644 tests/ClientTest.php create mode 100644 tests/Fixtures/action_authentication_denied.json create mode 100644 tests/Fixtures/action_authentication_denied_context.json create mode 100644 tests/Fixtures/action_authentication_denied_context_actor.json create mode 100644 tests/Fixtures/action_authentication_denied_context_google_analytics_session.json create mode 100644 tests/Fixtures/action_authentication_denied_data.json create mode 100644 tests/Fixtures/action_user_registration_denied.json create mode 100644 tests/Fixtures/action_user_registration_denied_context.json create mode 100644 tests/Fixtures/action_user_registration_denied_context_actor.json create mode 100644 tests/Fixtures/action_user_registration_denied_context_google_analytics_session.json create mode 100644 tests/Fixtures/action_user_registration_denied_data.json create mode 100644 tests/Fixtures/add_role_permission.json create mode 100644 tests/Fixtures/api_key.json create mode 100644 tests/Fixtures/api_key_created.json create mode 100644 tests/Fixtures/api_key_created_context.json create mode 100644 tests/Fixtures/api_key_created_context_actor.json create mode 100644 tests/Fixtures/api_key_created_context_google_analytics_session.json create mode 100644 tests/Fixtures/api_key_created_data.json create mode 100644 tests/Fixtures/api_key_created_data_owner.json create mode 100644 tests/Fixtures/api_key_list_list_metadata.json create mode 100644 tests/Fixtures/api_key_owner.json create mode 100644 tests/Fixtures/api_key_revoked.json create mode 100644 tests/Fixtures/api_key_revoked_context.json create mode 100644 tests/Fixtures/api_key_revoked_context_actor.json create mode 100644 tests/Fixtures/api_key_revoked_context_google_analytics_session.json create mode 100644 tests/Fixtures/api_key_revoked_data.json create mode 100644 tests/Fixtures/api_key_revoked_data_owner.json create mode 100644 tests/Fixtures/api_key_validation_response.json create mode 100644 tests/Fixtures/api_key_with_value.json create mode 100644 tests/Fixtures/api_key_with_value_owner.json create mode 100644 tests/Fixtures/application_credentials_list_item.json create mode 100644 tests/Fixtures/assign_role.json create mode 100644 tests/Fixtures/audit_log_action_json.json create mode 100644 tests/Fixtures/audit_log_configuration.json create mode 100644 tests/Fixtures/audit_log_configuration_log_stream.json create mode 100644 tests/Fixtures/audit_log_event.json create mode 100644 tests/Fixtures/audit_log_event_actor.json create mode 100644 tests/Fixtures/audit_log_event_context.json create mode 100644 tests/Fixtures/audit_log_event_create_response.json create mode 100644 tests/Fixtures/audit_log_event_ingestion.json create mode 100644 tests/Fixtures/audit_log_event_target.json create mode 100644 tests/Fixtures/audit_log_export_creation.json create mode 100644 tests/Fixtures/audit_log_export_json.json create mode 100644 tests/Fixtures/audit_log_schema.json create mode 100644 tests/Fixtures/audit_log_schema_actor.json create mode 100644 tests/Fixtures/audit_log_schema_json.json create mode 100644 tests/Fixtures/audit_log_schema_json_actor.json create mode 100644 tests/Fixtures/audit_log_schema_json_target.json create mode 100644 tests/Fixtures/audit_log_schema_target.json create mode 100644 tests/Fixtures/audit_logs_retention_json.json create mode 100644 tests/Fixtures/authenticate_response.json create mode 100644 tests/Fixtures/authenticate_response_impersonator.json create mode 100644 tests/Fixtures/authenticate_response_oauth_token.json create mode 100644 tests/Fixtures/authentication_challenge.json create mode 100644 tests/Fixtures/authentication_challenge_verify_response.json create mode 100644 tests/Fixtures/authentication_challenges_verify_request.json create mode 100644 tests/Fixtures/authentication_email_verification_failed.json create mode 100644 tests/Fixtures/authentication_email_verification_failed_context.json create mode 100644 tests/Fixtures/authentication_email_verification_failed_context_actor.json create mode 100644 tests/Fixtures/authentication_email_verification_failed_context_google_analytics_session.json create mode 100644 tests/Fixtures/authentication_email_verification_failed_data.json create mode 100644 tests/Fixtures/authentication_email_verification_failed_data_error.json create mode 100644 tests/Fixtures/authentication_email_verification_succeeded.json create mode 100644 tests/Fixtures/authentication_email_verification_succeeded_context.json create mode 100644 tests/Fixtures/authentication_email_verification_succeeded_context_actor.json create mode 100644 tests/Fixtures/authentication_email_verification_succeeded_context_google_analytics_session.json create mode 100644 tests/Fixtures/authentication_email_verification_succeeded_data.json create mode 100644 tests/Fixtures/authentication_factor.json create mode 100644 tests/Fixtures/authentication_factor_enrolled.json create mode 100644 tests/Fixtures/authentication_factor_enrolled_sms.json create mode 100644 tests/Fixtures/authentication_factor_enrolled_totp.json create mode 100644 tests/Fixtures/authentication_factor_sms.json create mode 100644 tests/Fixtures/authentication_factor_totp.json create mode 100644 tests/Fixtures/authentication_factors_create_request.json create mode 100644 tests/Fixtures/authentication_magic_auth_failed.json create mode 100644 tests/Fixtures/authentication_magic_auth_failed_context.json create mode 100644 tests/Fixtures/authentication_magic_auth_failed_context_actor.json create mode 100644 tests/Fixtures/authentication_magic_auth_failed_context_google_analytics_session.json create mode 100644 tests/Fixtures/authentication_magic_auth_failed_data.json create mode 100644 tests/Fixtures/authentication_magic_auth_failed_data_error.json create mode 100644 tests/Fixtures/authentication_magic_auth_succeeded.json create mode 100644 tests/Fixtures/authentication_magic_auth_succeeded_context.json create mode 100644 tests/Fixtures/authentication_magic_auth_succeeded_context_actor.json create mode 100644 tests/Fixtures/authentication_magic_auth_succeeded_context_google_analytics_session.json create mode 100644 tests/Fixtures/authentication_magic_auth_succeeded_data.json create mode 100644 tests/Fixtures/authentication_mfa_failed.json create mode 100644 tests/Fixtures/authentication_mfa_failed_context.json create mode 100644 tests/Fixtures/authentication_mfa_failed_context_actor.json create mode 100644 tests/Fixtures/authentication_mfa_failed_context_google_analytics_session.json create mode 100644 tests/Fixtures/authentication_mfa_failed_data.json create mode 100644 tests/Fixtures/authentication_mfa_failed_data_error.json create mode 100644 tests/Fixtures/authentication_mfa_succeeded.json create mode 100644 tests/Fixtures/authentication_mfa_succeeded_context.json create mode 100644 tests/Fixtures/authentication_mfa_succeeded_context_actor.json create mode 100644 tests/Fixtures/authentication_mfa_succeeded_context_google_analytics_session.json create mode 100644 tests/Fixtures/authentication_mfa_succeeded_data.json create mode 100644 tests/Fixtures/authentication_oauth_failed.json create mode 100644 tests/Fixtures/authentication_oauth_failed_context.json create mode 100644 tests/Fixtures/authentication_oauth_failed_context_actor.json create mode 100644 tests/Fixtures/authentication_oauth_failed_context_google_analytics_session.json create mode 100644 tests/Fixtures/authentication_oauth_failed_data.json create mode 100644 tests/Fixtures/authentication_oauth_failed_data_error.json create mode 100644 tests/Fixtures/authentication_oauth_succeeded.json create mode 100644 tests/Fixtures/authentication_oauth_succeeded_context.json create mode 100644 tests/Fixtures/authentication_oauth_succeeded_context_actor.json create mode 100644 tests/Fixtures/authentication_oauth_succeeded_context_google_analytics_session.json create mode 100644 tests/Fixtures/authentication_oauth_succeeded_data.json create mode 100644 tests/Fixtures/authentication_passkey_failed.json create mode 100644 tests/Fixtures/authentication_passkey_failed_context.json create mode 100644 tests/Fixtures/authentication_passkey_failed_context_actor.json create mode 100644 tests/Fixtures/authentication_passkey_failed_context_google_analytics_session.json create mode 100644 tests/Fixtures/authentication_passkey_failed_data.json create mode 100644 tests/Fixtures/authentication_passkey_failed_data_error.json create mode 100644 tests/Fixtures/authentication_passkey_succeeded.json create mode 100644 tests/Fixtures/authentication_passkey_succeeded_context.json create mode 100644 tests/Fixtures/authentication_passkey_succeeded_context_actor.json create mode 100644 tests/Fixtures/authentication_passkey_succeeded_context_google_analytics_session.json create mode 100644 tests/Fixtures/authentication_passkey_succeeded_data.json create mode 100644 tests/Fixtures/authentication_password_failed.json create mode 100644 tests/Fixtures/authentication_password_failed_context.json create mode 100644 tests/Fixtures/authentication_password_failed_context_actor.json create mode 100644 tests/Fixtures/authentication_password_failed_context_google_analytics_session.json create mode 100644 tests/Fixtures/authentication_password_failed_data.json create mode 100644 tests/Fixtures/authentication_password_failed_data_error.json create mode 100644 tests/Fixtures/authentication_password_succeeded.json create mode 100644 tests/Fixtures/authentication_password_succeeded_context.json create mode 100644 tests/Fixtures/authentication_password_succeeded_context_actor.json create mode 100644 tests/Fixtures/authentication_password_succeeded_context_google_analytics_session.json create mode 100644 tests/Fixtures/authentication_password_succeeded_data.json create mode 100644 tests/Fixtures/authentication_radar_risk_detected.json create mode 100644 tests/Fixtures/authentication_radar_risk_detected_context.json create mode 100644 tests/Fixtures/authentication_radar_risk_detected_context_actor.json create mode 100644 tests/Fixtures/authentication_radar_risk_detected_context_google_analytics_session.json create mode 100644 tests/Fixtures/authentication_radar_risk_detected_data.json create mode 100644 tests/Fixtures/authentication_sso_failed.json create mode 100644 tests/Fixtures/authentication_sso_failed_context.json create mode 100644 tests/Fixtures/authentication_sso_failed_context_actor.json create mode 100644 tests/Fixtures/authentication_sso_failed_context_google_analytics_session.json create mode 100644 tests/Fixtures/authentication_sso_failed_data.json create mode 100644 tests/Fixtures/authentication_sso_failed_data_error.json create mode 100644 tests/Fixtures/authentication_sso_failed_data_sso.json create mode 100644 tests/Fixtures/authentication_sso_started.json create mode 100644 tests/Fixtures/authentication_sso_started_context.json create mode 100644 tests/Fixtures/authentication_sso_started_context_actor.json create mode 100644 tests/Fixtures/authentication_sso_started_context_google_analytics_session.json create mode 100644 tests/Fixtures/authentication_sso_started_data.json create mode 100644 tests/Fixtures/authentication_sso_started_data_sso.json create mode 100644 tests/Fixtures/authentication_sso_succeeded.json create mode 100644 tests/Fixtures/authentication_sso_succeeded_context.json create mode 100644 tests/Fixtures/authentication_sso_succeeded_context_actor.json create mode 100644 tests/Fixtures/authentication_sso_succeeded_context_google_analytics_session.json create mode 100644 tests/Fixtures/authentication_sso_succeeded_data.json create mode 100644 tests/Fixtures/authentication_sso_succeeded_data_sso.json create mode 100644 tests/Fixtures/authentication_sso_timed_out.json create mode 100644 tests/Fixtures/authentication_sso_timed_out_context.json create mode 100644 tests/Fixtures/authentication_sso_timed_out_context_actor.json create mode 100644 tests/Fixtures/authentication_sso_timed_out_context_google_analytics_session.json create mode 100644 tests/Fixtures/authentication_sso_timed_out_data.json create mode 100644 tests/Fixtures/authentication_sso_timed_out_data_error.json create mode 100644 tests/Fixtures/authentication_sso_timed_out_data_sso.json create mode 100644 tests/Fixtures/authorization_check.json create mode 100644 tests/Fixtures/authorization_code_session_authenticate_request.json create mode 100644 tests/Fixtures/authorization_permission.json create mode 100644 tests/Fixtures/authorization_permission_list_list_metadata.json create mode 100644 tests/Fixtures/authorization_resource.json create mode 100644 tests/Fixtures/authorization_resource_list_list_metadata.json create mode 100644 tests/Fixtures/authorized_connect_application_list_data.json create mode 100644 tests/Fixtures/authorized_connect_application_list_list_metadata.json create mode 100644 tests/Fixtures/challenge_authentication_factor.json create mode 100644 tests/Fixtures/check_authorization.json create mode 100644 tests/Fixtures/confirm_email_change.json create mode 100644 tests/Fixtures/connect_application.json create mode 100644 tests/Fixtures/connect_application_list_list_metadata.json create mode 100644 tests/Fixtures/connected_account.json create mode 100644 tests/Fixtures/connection.json create mode 100644 tests/Fixtures/connection_activated.json create mode 100644 tests/Fixtures/connection_activated_context.json create mode 100644 tests/Fixtures/connection_activated_context_actor.json create mode 100644 tests/Fixtures/connection_activated_context_google_analytics_session.json create mode 100644 tests/Fixtures/connection_activated_data.json create mode 100644 tests/Fixtures/connection_activated_data_domain.json create mode 100644 tests/Fixtures/connection_deactivated.json create mode 100644 tests/Fixtures/connection_deactivated_context.json create mode 100644 tests/Fixtures/connection_deactivated_context_actor.json create mode 100644 tests/Fixtures/connection_deactivated_context_google_analytics_session.json create mode 100644 tests/Fixtures/connection_deactivated_data.json create mode 100644 tests/Fixtures/connection_deactivated_data_domain.json create mode 100644 tests/Fixtures/connection_deleted.json create mode 100644 tests/Fixtures/connection_deleted_context.json create mode 100644 tests/Fixtures/connection_deleted_context_actor.json create mode 100644 tests/Fixtures/connection_deleted_context_google_analytics_session.json create mode 100644 tests/Fixtures/connection_deleted_data.json create mode 100644 tests/Fixtures/connection_domain.json create mode 100644 tests/Fixtures/connection_list_list_metadata.json create mode 100644 tests/Fixtures/connection_option.json create mode 100644 tests/Fixtures/connection_saml_certificate_renewal_required.json create mode 100644 tests/Fixtures/connection_saml_certificate_renewal_required_context.json create mode 100644 tests/Fixtures/connection_saml_certificate_renewal_required_context_actor.json create mode 100644 tests/Fixtures/connection_saml_certificate_renewal_required_context_google_analytics_session.json create mode 100644 tests/Fixtures/connection_saml_certificate_renewal_required_data.json create mode 100644 tests/Fixtures/connection_saml_certificate_renewal_required_data_certificate.json create mode 100644 tests/Fixtures/connection_saml_certificate_renewal_required_data_connection.json create mode 100644 tests/Fixtures/connection_saml_certificate_renewed.json create mode 100644 tests/Fixtures/connection_saml_certificate_renewed_context.json create mode 100644 tests/Fixtures/connection_saml_certificate_renewed_context_actor.json create mode 100644 tests/Fixtures/connection_saml_certificate_renewed_context_google_analytics_session.json create mode 100644 tests/Fixtures/connection_saml_certificate_renewed_data.json create mode 100644 tests/Fixtures/connection_saml_certificate_renewed_data_certificate.json create mode 100644 tests/Fixtures/connection_saml_certificate_renewed_data_connection.json create mode 100644 tests/Fixtures/cors_origin_response.json create mode 100644 tests/Fixtures/create_application_secret.json create mode 100644 tests/Fixtures/create_authorization_permission.json create mode 100644 tests/Fixtures/create_authorization_resource.json create mode 100644 tests/Fixtures/create_cors_origin.json create mode 100644 tests/Fixtures/create_m2m_application.json create mode 100644 tests/Fixtures/create_magic_code_and_return.json create mode 100644 tests/Fixtures/create_oauth_application.json create mode 100644 tests/Fixtures/create_organization_api_key.json create mode 100644 tests/Fixtures/create_organization_domain.json create mode 100644 tests/Fixtures/create_organization_role.json create mode 100644 tests/Fixtures/create_password_reset.json create mode 100644 tests/Fixtures/create_password_reset_token.json create mode 100644 tests/Fixtures/create_redirect_uri.json create mode 100644 tests/Fixtures/create_role.json create mode 100644 tests/Fixtures/create_user.json create mode 100644 tests/Fixtures/create_user_invite_options.json create mode 100644 tests/Fixtures/create_user_organization_membership.json create mode 100644 tests/Fixtures/create_webhook_endpoint.json create mode 100644 tests/Fixtures/data_integration_access_token_response.json create mode 100644 tests/Fixtures/data_integration_authorize_url_response.json create mode 100644 tests/Fixtures/data_integrations_get_data_integration_authorize_url_request.json create mode 100644 tests/Fixtures/data_integrations_get_user_token_request.json create mode 100644 tests/Fixtures/data_integrations_list_response.json create mode 100644 tests/Fixtures/data_integrations_list_response_data.json create mode 100644 tests/Fixtures/data_integrations_list_response_data_connected_account.json create mode 100644 tests/Fixtures/device_authorization_response.json create mode 100644 tests/Fixtures/device_code_session_authenticate_request.json create mode 100644 tests/Fixtures/directory.json create mode 100644 tests/Fixtures/directory_group.json create mode 100644 tests/Fixtures/directory_group_list_list_metadata.json create mode 100644 tests/Fixtures/directory_list_list_metadata.json create mode 100644 tests/Fixtures/directory_metadata.json create mode 100644 tests/Fixtures/directory_metadata_user.json create mode 100644 tests/Fixtures/directory_user.json create mode 100644 tests/Fixtures/directory_user_email.json create mode 100644 tests/Fixtures/directory_user_list_list_metadata.json create mode 100644 tests/Fixtures/directory_user_with_groups.json create mode 100644 tests/Fixtures/directory_user_with_groups_email.json create mode 100644 tests/Fixtures/dsync_activated.json create mode 100644 tests/Fixtures/dsync_activated_context.json create mode 100644 tests/Fixtures/dsync_activated_context_actor.json create mode 100644 tests/Fixtures/dsync_activated_context_google_analytics_session.json create mode 100644 tests/Fixtures/dsync_activated_data.json create mode 100644 tests/Fixtures/dsync_activated_data_domain.json create mode 100644 tests/Fixtures/dsync_deactivated.json create mode 100644 tests/Fixtures/dsync_deactivated_context.json create mode 100644 tests/Fixtures/dsync_deactivated_context_actor.json create mode 100644 tests/Fixtures/dsync_deactivated_context_google_analytics_session.json create mode 100644 tests/Fixtures/dsync_deactivated_data.json create mode 100644 tests/Fixtures/dsync_deactivated_data_domain.json create mode 100644 tests/Fixtures/dsync_deleted.json create mode 100644 tests/Fixtures/dsync_deleted_context.json create mode 100644 tests/Fixtures/dsync_deleted_context_actor.json create mode 100644 tests/Fixtures/dsync_deleted_context_google_analytics_session.json create mode 100644 tests/Fixtures/dsync_deleted_data.json create mode 100644 tests/Fixtures/dsync_group_created.json create mode 100644 tests/Fixtures/dsync_group_created_context.json create mode 100644 tests/Fixtures/dsync_group_created_context_actor.json create mode 100644 tests/Fixtures/dsync_group_created_context_google_analytics_session.json create mode 100644 tests/Fixtures/dsync_group_created_data.json create mode 100644 tests/Fixtures/dsync_group_deleted.json create mode 100644 tests/Fixtures/dsync_group_deleted_context.json create mode 100644 tests/Fixtures/dsync_group_deleted_context_actor.json create mode 100644 tests/Fixtures/dsync_group_deleted_context_google_analytics_session.json create mode 100644 tests/Fixtures/dsync_group_deleted_data.json create mode 100644 tests/Fixtures/dsync_group_updated.json create mode 100644 tests/Fixtures/dsync_group_updated_context.json create mode 100644 tests/Fixtures/dsync_group_updated_context_actor.json create mode 100644 tests/Fixtures/dsync_group_updated_context_google_analytics_session.json create mode 100644 tests/Fixtures/dsync_group_updated_data.json create mode 100644 tests/Fixtures/dsync_group_user_added.json create mode 100644 tests/Fixtures/dsync_group_user_added_context.json create mode 100644 tests/Fixtures/dsync_group_user_added_context_actor.json create mode 100644 tests/Fixtures/dsync_group_user_added_context_google_analytics_session.json create mode 100644 tests/Fixtures/dsync_group_user_added_data.json create mode 100644 tests/Fixtures/dsync_group_user_added_data_group.json create mode 100644 tests/Fixtures/dsync_group_user_added_data_user.json create mode 100644 tests/Fixtures/dsync_group_user_added_data_user_email.json create mode 100644 tests/Fixtures/dsync_group_user_added_data_user_role.json create mode 100644 tests/Fixtures/dsync_group_user_removed.json create mode 100644 tests/Fixtures/dsync_group_user_removed_context.json create mode 100644 tests/Fixtures/dsync_group_user_removed_context_actor.json create mode 100644 tests/Fixtures/dsync_group_user_removed_context_google_analytics_session.json create mode 100644 tests/Fixtures/dsync_group_user_removed_data.json create mode 100644 tests/Fixtures/dsync_group_user_removed_data_group.json create mode 100644 tests/Fixtures/dsync_group_user_removed_data_user.json create mode 100644 tests/Fixtures/dsync_group_user_removed_data_user_email.json create mode 100644 tests/Fixtures/dsync_group_user_removed_data_user_role.json create mode 100644 tests/Fixtures/dsync_user_created.json create mode 100644 tests/Fixtures/dsync_user_created_context.json create mode 100644 tests/Fixtures/dsync_user_created_context_actor.json create mode 100644 tests/Fixtures/dsync_user_created_context_google_analytics_session.json create mode 100644 tests/Fixtures/dsync_user_created_data.json create mode 100644 tests/Fixtures/dsync_user_created_data_email.json create mode 100644 tests/Fixtures/dsync_user_created_data_role.json create mode 100644 tests/Fixtures/dsync_user_deleted.json create mode 100644 tests/Fixtures/dsync_user_deleted_context.json create mode 100644 tests/Fixtures/dsync_user_deleted_context_actor.json create mode 100644 tests/Fixtures/dsync_user_deleted_context_google_analytics_session.json create mode 100644 tests/Fixtures/dsync_user_deleted_data.json create mode 100644 tests/Fixtures/dsync_user_deleted_data_email.json create mode 100644 tests/Fixtures/dsync_user_deleted_data_role.json create mode 100644 tests/Fixtures/dsync_user_updated.json create mode 100644 tests/Fixtures/dsync_user_updated_context.json create mode 100644 tests/Fixtures/dsync_user_updated_context_actor.json create mode 100644 tests/Fixtures/dsync_user_updated_context_google_analytics_session.json create mode 100644 tests/Fixtures/dsync_user_updated_data.json create mode 100644 tests/Fixtures/dsync_user_updated_data_email.json create mode 100644 tests/Fixtures/dsync_user_updated_data_role.json create mode 100644 tests/Fixtures/email_change.json create mode 100644 tests/Fixtures/email_change_confirmation.json create mode 100644 tests/Fixtures/email_change_confirmation_user.json create mode 100644 tests/Fixtures/email_verification.json create mode 100644 tests/Fixtures/email_verification_code_session_authenticate_request.json create mode 100644 tests/Fixtures/email_verification_created.json create mode 100644 tests/Fixtures/email_verification_created_context.json create mode 100644 tests/Fixtures/email_verification_created_context_actor.json create mode 100644 tests/Fixtures/email_verification_created_context_google_analytics_session.json create mode 100644 tests/Fixtures/email_verification_created_data.json create mode 100644 tests/Fixtures/enroll_user_authentication_factor.json create mode 100644 tests/Fixtures/event_context.json create mode 100644 tests/Fixtures/event_context_actor.json create mode 100644 tests/Fixtures/event_context_google_analytics_session.json create mode 100644 tests/Fixtures/event_list_list_metadata.json create mode 100644 tests/Fixtures/event_schema.json create mode 100644 tests/Fixtures/external_auth_complete_response.json create mode 100644 tests/Fixtures/feature_flag.json create mode 100644 tests/Fixtures/feature_flag_owner.json create mode 100644 tests/Fixtures/flag.json create mode 100644 tests/Fixtures/flag_created.json create mode 100644 tests/Fixtures/flag_created_context.json create mode 100644 tests/Fixtures/flag_created_context_actor.json create mode 100644 tests/Fixtures/flag_created_data.json create mode 100644 tests/Fixtures/flag_created_data_owner.json create mode 100644 tests/Fixtures/flag_deleted.json create mode 100644 tests/Fixtures/flag_deleted_context.json create mode 100644 tests/Fixtures/flag_deleted_context_actor.json create mode 100644 tests/Fixtures/flag_deleted_data.json create mode 100644 tests/Fixtures/flag_deleted_data_owner.json create mode 100644 tests/Fixtures/flag_list_list_metadata.json create mode 100644 tests/Fixtures/flag_owner.json create mode 100644 tests/Fixtures/flag_rule_updated.json create mode 100644 tests/Fixtures/flag_rule_updated_context.json create mode 100644 tests/Fixtures/flag_rule_updated_context_actor.json create mode 100644 tests/Fixtures/flag_rule_updated_context_configured_target.json create mode 100644 tests/Fixtures/flag_rule_updated_context_configured_target_organization.json create mode 100644 tests/Fixtures/flag_rule_updated_context_configured_target_user.json create mode 100644 tests/Fixtures/flag_rule_updated_context_previous_attribute.json create mode 100644 tests/Fixtures/flag_rule_updated_context_previous_attribute_context.json create mode 100644 tests/Fixtures/flag_rule_updated_context_previous_attribute_context_configured_target.json create mode 100644 tests/Fixtures/flag_rule_updated_context_previous_attribute_context_configured_target_organization.json create mode 100644 tests/Fixtures/flag_rule_updated_context_previous_attribute_context_configured_target_user.json create mode 100644 tests/Fixtures/flag_rule_updated_context_previous_attribute_data.json create mode 100644 tests/Fixtures/flag_rule_updated_data.json create mode 100644 tests/Fixtures/flag_rule_updated_data_owner.json create mode 100644 tests/Fixtures/flag_updated.json create mode 100644 tests/Fixtures/flag_updated_context.json create mode 100644 tests/Fixtures/flag_updated_context_actor.json create mode 100644 tests/Fixtures/flag_updated_context_previous_attribute.json create mode 100644 tests/Fixtures/flag_updated_context_previous_attribute_data.json create mode 100644 tests/Fixtures/flag_updated_data.json create mode 100644 tests/Fixtures/flag_updated_data_owner.json create mode 100644 tests/Fixtures/generate_link.json create mode 100644 tests/Fixtures/intent_options.json create mode 100644 tests/Fixtures/invitation.json create mode 100644 tests/Fixtures/invitation_accepted.json create mode 100644 tests/Fixtures/invitation_accepted_context.json create mode 100644 tests/Fixtures/invitation_accepted_context_actor.json create mode 100644 tests/Fixtures/invitation_accepted_context_google_analytics_session.json create mode 100644 tests/Fixtures/invitation_accepted_data.json create mode 100644 tests/Fixtures/invitation_created.json create mode 100644 tests/Fixtures/invitation_created_context.json create mode 100644 tests/Fixtures/invitation_created_context_actor.json create mode 100644 tests/Fixtures/invitation_created_context_google_analytics_session.json create mode 100644 tests/Fixtures/invitation_created_data.json create mode 100644 tests/Fixtures/invitation_resent.json create mode 100644 tests/Fixtures/invitation_resent_context.json create mode 100644 tests/Fixtures/invitation_resent_context_actor.json create mode 100644 tests/Fixtures/invitation_resent_context_google_analytics_session.json create mode 100644 tests/Fixtures/invitation_resent_data.json create mode 100644 tests/Fixtures/invitation_revoked.json create mode 100644 tests/Fixtures/invitation_revoked_context.json create mode 100644 tests/Fixtures/invitation_revoked_context_actor.json create mode 100644 tests/Fixtures/invitation_revoked_context_google_analytics_session.json create mode 100644 tests/Fixtures/invitation_revoked_data.json create mode 100644 tests/Fixtures/jwks_response.json create mode 100644 tests/Fixtures/jwks_response_keys.json create mode 100644 tests/Fixtures/jwt_template_response.json create mode 100644 tests/Fixtures/list.json create mode 100644 tests/Fixtures/list_api_key.json create mode 100644 tests/Fixtures/list_audit_log_action_json.json create mode 100644 tests/Fixtures/list_audit_log_schema_json.json create mode 100644 tests/Fixtures/list_authentication_factor.json create mode 100644 tests/Fixtures/list_authorization_permission.json create mode 100644 tests/Fixtures/list_authorization_resource.json create mode 100644 tests/Fixtures/list_authorized_connect_application_list_data.json create mode 100644 tests/Fixtures/list_connect_application.json create mode 100644 tests/Fixtures/list_connection.json create mode 100644 tests/Fixtures/list_data.json create mode 100644 tests/Fixtures/list_directory.json create mode 100644 tests/Fixtures/list_directory_group.json create mode 100644 tests/Fixtures/list_directory_user_with_groups.json create mode 100644 tests/Fixtures/list_event_schema.json create mode 100644 tests/Fixtures/list_flag.json create mode 100644 tests/Fixtures/list_organization.json create mode 100644 tests/Fixtures/list_role_assignment.json create mode 100644 tests/Fixtures/list_user.json create mode 100644 tests/Fixtures/list_user_invite.json create mode 100644 tests/Fixtures/list_user_organization_membership.json create mode 100644 tests/Fixtures/list_user_organization_membership_base_list_data.json create mode 100644 tests/Fixtures/list_user_sessions_list_item.json create mode 100644 tests/Fixtures/list_webhook_endpoint_json.json create mode 100644 tests/Fixtures/magic_auth.json create mode 100644 tests/Fixtures/magic_auth_code_session_authenticate_request.json create mode 100644 tests/Fixtures/magic_auth_created.json create mode 100644 tests/Fixtures/magic_auth_created_context.json create mode 100644 tests/Fixtures/magic_auth_created_context_actor.json create mode 100644 tests/Fixtures/magic_auth_created_context_google_analytics_session.json create mode 100644 tests/Fixtures/magic_auth_created_data.json create mode 100644 tests/Fixtures/mfa_totp_session_authenticate_request.json create mode 100644 tests/Fixtures/new_connect_application_secret.json create mode 100644 tests/Fixtures/organization.json create mode 100644 tests/Fixtures/organization_created.json create mode 100644 tests/Fixtures/organization_created_context.json create mode 100644 tests/Fixtures/organization_created_context_actor.json create mode 100644 tests/Fixtures/organization_created_context_google_analytics_session.json create mode 100644 tests/Fixtures/organization_created_data.json create mode 100644 tests/Fixtures/organization_created_data_domain.json create mode 100644 tests/Fixtures/organization_deleted.json create mode 100644 tests/Fixtures/organization_deleted_context.json create mode 100644 tests/Fixtures/organization_deleted_context_actor.json create mode 100644 tests/Fixtures/organization_deleted_context_google_analytics_session.json create mode 100644 tests/Fixtures/organization_deleted_data.json create mode 100644 tests/Fixtures/organization_deleted_data_domain.json create mode 100644 tests/Fixtures/organization_domain.json create mode 100644 tests/Fixtures/organization_domain_created.json create mode 100644 tests/Fixtures/organization_domain_created_context.json create mode 100644 tests/Fixtures/organization_domain_created_context_actor.json create mode 100644 tests/Fixtures/organization_domain_created_context_google_analytics_session.json create mode 100644 tests/Fixtures/organization_domain_created_data.json create mode 100644 tests/Fixtures/organization_domain_data.json create mode 100644 tests/Fixtures/organization_domain_deleted.json create mode 100644 tests/Fixtures/organization_domain_deleted_context.json create mode 100644 tests/Fixtures/organization_domain_deleted_context_actor.json create mode 100644 tests/Fixtures/organization_domain_deleted_context_google_analytics_session.json create mode 100644 tests/Fixtures/organization_domain_deleted_data.json create mode 100644 tests/Fixtures/organization_domain_stand_alone.json create mode 100644 tests/Fixtures/organization_domain_updated.json create mode 100644 tests/Fixtures/organization_domain_updated_context.json create mode 100644 tests/Fixtures/organization_domain_updated_context_actor.json create mode 100644 tests/Fixtures/organization_domain_updated_context_google_analytics_session.json create mode 100644 tests/Fixtures/organization_domain_updated_data.json create mode 100644 tests/Fixtures/organization_domain_verification_failed.json create mode 100644 tests/Fixtures/organization_domain_verification_failed_context.json create mode 100644 tests/Fixtures/organization_domain_verification_failed_context_actor.json create mode 100644 tests/Fixtures/organization_domain_verification_failed_context_google_analytics_session.json create mode 100644 tests/Fixtures/organization_domain_verification_failed_data.json create mode 100644 tests/Fixtures/organization_domain_verification_failed_data_organization_domain.json create mode 100644 tests/Fixtures/organization_domain_verified.json create mode 100644 tests/Fixtures/organization_domain_verified_context.json create mode 100644 tests/Fixtures/organization_domain_verified_context_actor.json create mode 100644 tests/Fixtures/organization_domain_verified_context_google_analytics_session.json create mode 100644 tests/Fixtures/organization_domain_verified_data.json create mode 100644 tests/Fixtures/organization_input.json create mode 100644 tests/Fixtures/organization_list_list_metadata.json create mode 100644 tests/Fixtures/organization_membership.json create mode 100644 tests/Fixtures/organization_membership_created.json create mode 100644 tests/Fixtures/organization_membership_created_context.json create mode 100644 tests/Fixtures/organization_membership_created_context_actor.json create mode 100644 tests/Fixtures/organization_membership_created_context_google_analytics_session.json create mode 100644 tests/Fixtures/organization_membership_created_data.json create mode 100644 tests/Fixtures/organization_membership_deleted.json create mode 100644 tests/Fixtures/organization_membership_deleted_context.json create mode 100644 tests/Fixtures/organization_membership_deleted_context_actor.json create mode 100644 tests/Fixtures/organization_membership_deleted_context_google_analytics_session.json create mode 100644 tests/Fixtures/organization_membership_deleted_data.json create mode 100644 tests/Fixtures/organization_membership_updated.json create mode 100644 tests/Fixtures/organization_membership_updated_context.json create mode 100644 tests/Fixtures/organization_membership_updated_context_actor.json create mode 100644 tests/Fixtures/organization_membership_updated_context_google_analytics_session.json create mode 100644 tests/Fixtures/organization_membership_updated_data.json create mode 100644 tests/Fixtures/organization_role_created.json create mode 100644 tests/Fixtures/organization_role_created_context.json create mode 100644 tests/Fixtures/organization_role_created_context_actor.json create mode 100644 tests/Fixtures/organization_role_created_context_google_analytics_session.json create mode 100644 tests/Fixtures/organization_role_created_data.json create mode 100644 tests/Fixtures/organization_role_deleted.json create mode 100644 tests/Fixtures/organization_role_deleted_context.json create mode 100644 tests/Fixtures/organization_role_deleted_context_actor.json create mode 100644 tests/Fixtures/organization_role_deleted_context_google_analytics_session.json create mode 100644 tests/Fixtures/organization_role_deleted_data.json create mode 100644 tests/Fixtures/organization_role_updated.json create mode 100644 tests/Fixtures/organization_role_updated_context.json create mode 100644 tests/Fixtures/organization_role_updated_context_actor.json create mode 100644 tests/Fixtures/organization_role_updated_context_google_analytics_session.json create mode 100644 tests/Fixtures/organization_role_updated_data.json create mode 100644 tests/Fixtures/organization_selection_session_authenticate_request.json create mode 100644 tests/Fixtures/organization_updated.json create mode 100644 tests/Fixtures/organization_updated_context.json create mode 100644 tests/Fixtures/organization_updated_context_actor.json create mode 100644 tests/Fixtures/organization_updated_context_google_analytics_session.json create mode 100644 tests/Fixtures/organization_updated_data.json create mode 100644 tests/Fixtures/organization_updated_data_domain.json create mode 100644 tests/Fixtures/password_reset.json create mode 100644 tests/Fixtures/password_reset_created.json create mode 100644 tests/Fixtures/password_reset_created_context.json create mode 100644 tests/Fixtures/password_reset_created_context_actor.json create mode 100644 tests/Fixtures/password_reset_created_context_google_analytics_session.json create mode 100644 tests/Fixtures/password_reset_created_data.json create mode 100644 tests/Fixtures/password_reset_succeeded.json create mode 100644 tests/Fixtures/password_reset_succeeded_context.json create mode 100644 tests/Fixtures/password_reset_succeeded_context_actor.json create mode 100644 tests/Fixtures/password_reset_succeeded_context_google_analytics_session.json create mode 100644 tests/Fixtures/password_reset_succeeded_data.json create mode 100644 tests/Fixtures/password_session_authenticate_request.json create mode 100644 tests/Fixtures/permission.json create mode 100644 tests/Fixtures/permission_created.json create mode 100644 tests/Fixtures/permission_created_context.json create mode 100644 tests/Fixtures/permission_created_context_actor.json create mode 100644 tests/Fixtures/permission_created_context_google_analytics_session.json create mode 100644 tests/Fixtures/permission_created_data.json create mode 100644 tests/Fixtures/permission_deleted.json create mode 100644 tests/Fixtures/permission_deleted_context.json create mode 100644 tests/Fixtures/permission_deleted_context_actor.json create mode 100644 tests/Fixtures/permission_deleted_context_google_analytics_session.json create mode 100644 tests/Fixtures/permission_deleted_data.json create mode 100644 tests/Fixtures/permission_updated.json create mode 100644 tests/Fixtures/permission_updated_context.json create mode 100644 tests/Fixtures/permission_updated_context_actor.json create mode 100644 tests/Fixtures/permission_updated_context_google_analytics_session.json create mode 100644 tests/Fixtures/permission_updated_data.json create mode 100644 tests/Fixtures/portal_link_response.json create mode 100644 tests/Fixtures/profile.json create mode 100644 tests/Fixtures/radar_list_entry_already_present_response.json create mode 100644 tests/Fixtures/radar_standalone_assess_request.json create mode 100644 tests/Fixtures/radar_standalone_delete_radar_list_entry_request.json create mode 100644 tests/Fixtures/radar_standalone_response.json create mode 100644 tests/Fixtures/radar_standalone_update_radar_attempt_request.json create mode 100644 tests/Fixtures/radar_standalone_update_radar_list_request.json create mode 100644 tests/Fixtures/redirect_uri.json create mode 100644 tests/Fixtures/redirect_uri_input.json create mode 100644 tests/Fixtures/refresh_token_session_authenticate_request.json create mode 100644 tests/Fixtures/remove_role.json create mode 100644 tests/Fixtures/resend_user_invite_options.json create mode 100644 tests/Fixtures/reset_password_response.json create mode 100644 tests/Fixtures/revoke_session.json create mode 100644 tests/Fixtures/role.json create mode 100644 tests/Fixtures/role_assignment.json create mode 100644 tests/Fixtures/role_assignment_list_list_metadata.json create mode 100644 tests/Fixtures/role_assignment_resource.json create mode 100644 tests/Fixtures/role_created.json create mode 100644 tests/Fixtures/role_created_context.json create mode 100644 tests/Fixtures/role_created_context_actor.json create mode 100644 tests/Fixtures/role_created_context_google_analytics_session.json create mode 100644 tests/Fixtures/role_created_data.json create mode 100644 tests/Fixtures/role_deleted.json create mode 100644 tests/Fixtures/role_deleted_context.json create mode 100644 tests/Fixtures/role_deleted_context_actor.json create mode 100644 tests/Fixtures/role_deleted_context_google_analytics_session.json create mode 100644 tests/Fixtures/role_deleted_data.json create mode 100644 tests/Fixtures/role_list.json create mode 100644 tests/Fixtures/role_updated.json create mode 100644 tests/Fixtures/role_updated_context.json create mode 100644 tests/Fixtures/role_updated_context_actor.json create mode 100644 tests/Fixtures/role_updated_context_google_analytics_session.json create mode 100644 tests/Fixtures/role_updated_data.json create mode 100644 tests/Fixtures/send_email_change.json create mode 100644 tests/Fixtures/send_verification_email_response.json create mode 100644 tests/Fixtures/session_created.json create mode 100644 tests/Fixtures/session_created_context.json create mode 100644 tests/Fixtures/session_created_context_actor.json create mode 100644 tests/Fixtures/session_created_context_google_analytics_session.json create mode 100644 tests/Fixtures/session_created_data.json create mode 100644 tests/Fixtures/session_created_data_impersonator.json create mode 100644 tests/Fixtures/session_revoked.json create mode 100644 tests/Fixtures/session_revoked_context.json create mode 100644 tests/Fixtures/session_revoked_context_actor.json create mode 100644 tests/Fixtures/session_revoked_context_google_analytics_session.json create mode 100644 tests/Fixtures/session_revoked_data.json create mode 100644 tests/Fixtures/session_revoked_data_impersonator.json create mode 100644 tests/Fixtures/set_role_permissions.json create mode 100644 tests/Fixtures/slim_role.json create mode 100644 tests/Fixtures/sso_authorize_url_response.json create mode 100644 tests/Fixtures/sso_device_authorization_request.json create mode 100644 tests/Fixtures/sso_intent_options.json create mode 100644 tests/Fixtures/sso_logout_authorize_request.json create mode 100644 tests/Fixtures/sso_logout_authorize_response.json create mode 100644 tests/Fixtures/sso_token_response.json create mode 100644 tests/Fixtures/sso_token_response_oauth_token.json create mode 100644 tests/Fixtures/token_query.json create mode 100644 tests/Fixtures/update_audit_logs_retention.json create mode 100644 tests/Fixtures/update_authorization_permission.json create mode 100644 tests/Fixtures/update_authorization_resource.json create mode 100644 tests/Fixtures/update_jwt_template.json create mode 100644 tests/Fixtures/update_oauth_application.json create mode 100644 tests/Fixtures/update_organization.json create mode 100644 tests/Fixtures/update_organization_role.json create mode 100644 tests/Fixtures/update_role.json create mode 100644 tests/Fixtures/update_user.json create mode 100644 tests/Fixtures/update_user_organization_membership.json create mode 100644 tests/Fixtures/update_webhook_endpoint.json create mode 100644 tests/Fixtures/user.json create mode 100644 tests/Fixtures/user_authentication_factor_enroll_response.json create mode 100644 tests/Fixtures/user_authentication_factor_list_list_metadata.json create mode 100644 tests/Fixtures/user_consent_option.json create mode 100644 tests/Fixtures/user_consent_option_choice.json create mode 100644 tests/Fixtures/user_created.json create mode 100644 tests/Fixtures/user_created_context.json create mode 100644 tests/Fixtures/user_created_context_actor.json create mode 100644 tests/Fixtures/user_created_context_google_analytics_session.json create mode 100644 tests/Fixtures/user_created_data.json create mode 100644 tests/Fixtures/user_deleted.json create mode 100644 tests/Fixtures/user_deleted_context.json create mode 100644 tests/Fixtures/user_deleted_context_actor.json create mode 100644 tests/Fixtures/user_deleted_context_google_analytics_session.json create mode 100644 tests/Fixtures/user_deleted_data.json create mode 100644 tests/Fixtures/user_identities_get_item.json create mode 100644 tests/Fixtures/user_invite.json create mode 100644 tests/Fixtures/user_list_list_metadata.json create mode 100644 tests/Fixtures/user_management_login_request.json create mode 100644 tests/Fixtures/user_object.json create mode 100644 tests/Fixtures/user_organization_membership.json create mode 100644 tests/Fixtures/user_organization_membership_base_list_data.json create mode 100644 tests/Fixtures/user_organization_membership_base_list_list_metadata.json create mode 100644 tests/Fixtures/user_sessions_impersonator.json create mode 100644 tests/Fixtures/user_sessions_list_item.json create mode 100644 tests/Fixtures/user_updated.json create mode 100644 tests/Fixtures/user_updated_context.json create mode 100644 tests/Fixtures/user_updated_context_actor.json create mode 100644 tests/Fixtures/user_updated_context_google_analytics_session.json create mode 100644 tests/Fixtures/user_updated_data.json create mode 100644 tests/Fixtures/validate_api_key.json create mode 100644 tests/Fixtures/vault_byok_key_verification_completed.json create mode 100644 tests/Fixtures/vault_byok_key_verification_completed_context.json create mode 100644 tests/Fixtures/vault_byok_key_verification_completed_context_actor.json create mode 100644 tests/Fixtures/vault_byok_key_verification_completed_context_google_analytics_session.json create mode 100644 tests/Fixtures/vault_byok_key_verification_completed_data.json create mode 100644 tests/Fixtures/vault_data_created.json create mode 100644 tests/Fixtures/vault_data_created_context.json create mode 100644 tests/Fixtures/vault_data_created_context_actor.json create mode 100644 tests/Fixtures/vault_data_created_context_google_analytics_session.json create mode 100644 tests/Fixtures/vault_data_created_data.json create mode 100644 tests/Fixtures/vault_data_deleted.json create mode 100644 tests/Fixtures/vault_data_deleted_context.json create mode 100644 tests/Fixtures/vault_data_deleted_context_actor.json create mode 100644 tests/Fixtures/vault_data_deleted_context_google_analytics_session.json create mode 100644 tests/Fixtures/vault_data_deleted_data.json create mode 100644 tests/Fixtures/vault_data_read.json create mode 100644 tests/Fixtures/vault_data_read_context.json create mode 100644 tests/Fixtures/vault_data_read_context_actor.json create mode 100644 tests/Fixtures/vault_data_read_context_google_analytics_session.json create mode 100644 tests/Fixtures/vault_data_read_data.json create mode 100644 tests/Fixtures/vault_data_updated.json create mode 100644 tests/Fixtures/vault_data_updated_context.json create mode 100644 tests/Fixtures/vault_data_updated_context_actor.json create mode 100644 tests/Fixtures/vault_data_updated_context_google_analytics_session.json create mode 100644 tests/Fixtures/vault_data_updated_data.json create mode 100644 tests/Fixtures/vault_dek_decrypted.json create mode 100644 tests/Fixtures/vault_dek_decrypted_context.json create mode 100644 tests/Fixtures/vault_dek_decrypted_context_actor.json create mode 100644 tests/Fixtures/vault_dek_decrypted_context_google_analytics_session.json create mode 100644 tests/Fixtures/vault_dek_decrypted_data.json create mode 100644 tests/Fixtures/vault_dek_read.json create mode 100644 tests/Fixtures/vault_dek_read_context.json create mode 100644 tests/Fixtures/vault_dek_read_context_actor.json create mode 100644 tests/Fixtures/vault_dek_read_context_google_analytics_session.json create mode 100644 tests/Fixtures/vault_dek_read_data.json create mode 100644 tests/Fixtures/vault_kek_created.json create mode 100644 tests/Fixtures/vault_kek_created_context.json create mode 100644 tests/Fixtures/vault_kek_created_context_actor.json create mode 100644 tests/Fixtures/vault_kek_created_context_google_analytics_session.json create mode 100644 tests/Fixtures/vault_kek_created_data.json create mode 100644 tests/Fixtures/vault_metadata_read.json create mode 100644 tests/Fixtures/vault_metadata_read_context.json create mode 100644 tests/Fixtures/vault_metadata_read_context_actor.json create mode 100644 tests/Fixtures/vault_metadata_read_context_google_analytics_session.json create mode 100644 tests/Fixtures/vault_metadata_read_data.json create mode 100644 tests/Fixtures/vault_names_listed.json create mode 100644 tests/Fixtures/vault_names_listed_context.json create mode 100644 tests/Fixtures/vault_names_listed_context_actor.json create mode 100644 tests/Fixtures/vault_names_listed_context_google_analytics_session.json create mode 100644 tests/Fixtures/vault_names_listed_data.json create mode 100644 tests/Fixtures/verify_email_address.json create mode 100644 tests/Fixtures/verify_email_response.json create mode 100644 tests/Fixtures/webhook_endpoint_json.json create mode 100644 tests/Fixtures/webhook_endpoint_list_list_metadata.json create mode 100644 tests/Fixtures/widget_session_token.json create mode 100644 tests/Fixtures/widget_session_token_response.json create mode 100644 tests/PKCEHelperTest.php create mode 100644 tests/PasswordlessTest.php create mode 100644 tests/Service/AdminPortalTest.php create mode 100644 tests/Service/ApiKeysTest.php create mode 100644 tests/Service/AuditLogsTest.php create mode 100644 tests/Service/AuthorizationTest.php create mode 100644 tests/Service/ConnectTest.php create mode 100644 tests/Service/DirectorySyncTest.php create mode 100644 tests/Service/EventsTest.php create mode 100644 tests/Service/FeatureFlagsTest.php create mode 100644 tests/Service/MultiFactorAuthTest.php create mode 100644 tests/Service/OrganizationDomainsTest.php create mode 100644 tests/Service/OrganizationsTest.php create mode 100644 tests/Service/PipesTest.php create mode 100644 tests/Service/RadarTest.php create mode 100644 tests/Service/RuntimeBehaviorTest.php create mode 100644 tests/Service/SSOTest.php create mode 100644 tests/Service/UserManagementTest.php create mode 100644 tests/Service/WebhooksTest.php create mode 100644 tests/Service/WidgetsTest.php create mode 100644 tests/SessionManagerTest.php create mode 100644 tests/VaultTest.php create mode 100644 tests/WebhookVerificationTest.php delete mode 100644 tests/WorkOS/AuditLogsTest.php delete mode 100644 tests/WorkOS/ClientTest.php delete mode 100644 tests/WorkOS/CookieSessionTest.php delete mode 100644 tests/WorkOS/DirectorySyncTest.php delete mode 100644 tests/WorkOS/MFATest.php delete mode 100644 tests/WorkOS/OrganizationsTest.php delete mode 100644 tests/WorkOS/PaginatedResourceTest.php delete mode 100644 tests/WorkOS/PasswordlessTest.php delete mode 100644 tests/WorkOS/PortalTest.php delete mode 100644 tests/WorkOS/RBACTest.php delete mode 100644 tests/WorkOS/Resource/WebhookResponseTest.php delete mode 100644 tests/WorkOS/SSOTest.php delete mode 100644 tests/WorkOS/Session/HaliteSessionEncryptionTest.php delete mode 100644 tests/WorkOS/Session/SigningOnlySessionHandlerTest.php delete mode 100644 tests/WorkOS/UserManagementTest.php delete mode 100644 tests/WorkOS/VaultTest.php delete mode 100644 tests/WorkOS/WebhookTest.php delete mode 100644 tests/WorkOS/WidgetsTest.php delete mode 100644 tests/WorkOS/WorkOSTest.php diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 00000000..7520a1fc --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,23 @@ +setRules([ + '@PSR12' => true, + 'ordered_imports' => ['sort_algorithm' => 'alpha'], + 'no_unused_imports' => true, + 'single_quote' => true, + 'trailing_comma_in_multiline' => true, + 'declare_strict_types' => true, + ]) + ->setRiskyAllowed(true) + ->setFinder( + (new Finder()) + ->in(__DIR__) + ->exclude(['vendor']) + ) +; diff --git a/composer.json b/composer.json index 195ae931..44343135 100644 --- a/composer.json +++ b/composer.json @@ -6,17 +6,19 @@ "authors": [ { "name": "WorkOS", - "email": "eng@workos.com" + "email": "sdk@workos.com" } ], "require": { - "php": ">=8.2.0", - "ext-curl": "*", + "php": "^8.2", + "ext-curl": "^8.2", + "guzzlehttp/guzzle": "^7.0", "paragonie/halite": "^5.1" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.0", - "phpunit/phpunit": "^10.5" + "phpstan/phpstan": "^2.1", + "phpunit/phpunit": "^11.5" }, "autoload": { "psr-4": { @@ -33,9 +35,11 @@ }, "scripts": { "clean": "rm -rf composer.lock vendor/", - "format": "php vendor/bin/php-cs-fixer fix -v --using-cache=no .", - "format-check": "php vendor/bin/php-cs-fixer fix -v --dry-run --using-cache=no .", - "test": "php vendor/bin/phpunit tests" + "format": "php vendor/bin/php-cs-fixer fix -v --using-cache=no --config=.php-cs-fixer.dist.php", + "format-check": "php vendor/bin/php-cs-fixer fix -v --dry-run --using-cache=no --config=.php-cs-fixer.dist.php", + "test": "php vendor/bin/phpunit tests", + "typecheck": "php vendor/bin/phpstan analyse --no-progress", + "ci": "./script/ci" }, "config": { "allow-plugins": { diff --git a/docs/V5_MIGRATION_GUIDE.md b/docs/V5_MIGRATION_GUIDE.md new file mode 100644 index 00000000..38a68321 --- /dev/null +++ b/docs/V5_MIGRATION_GUIDE.md @@ -0,0 +1,812 @@ +# WorkOS PHP SDK v5 Migration Guide + +This guide covers the changes required to migrate from the v4 PHP SDK to the next major release of `workos/workos-php`. + +The biggest change is architectural: the SDK is now centered around an instantiated [`WorkOS`](../lib/WorkOS.php) client with typed request/response models, lazy client methods like `sso()` and `userManagement()`, and a Guzzle-based HTTP runtime. + +## Table of Contents + +- [Quick Start](#quick-start) +- [PHP and Dependency Requirements](#php-and-dependency-requirements) +- [Biggest Conceptual Changes](#biggest-conceptual-changes) +- [Breaking Changes by Area](#breaking-changes-by-area) +- [New Features and Additions](#new-features-and-additions) +- [Testing Your Migration](#testing-your-migration) + +--- + +## Quick Start + +1. Upgrade to PHP 8.2 or newer. +2. Upgrade the package: + +```bash +composer require workos/workos-php:^5 +``` + +3. Replace direct class instantiation with a `WorkOS` client: + +```php +use WorkOS\WorkOS; + +$workos = new WorkOS( + apiKey: getenv('WORKOS_API_KEY'), + clientId: getenv('WORKOS_CLIENT_ID'), +); +``` + +4. Update renamed APIs and methods. +5. Re-run your tests and verify auth, SSO, invitations, and webhook flows end-to-end. + +--- + +## PHP and Dependency Requirements + +### Minimum PHP version is now 8.2+ + +v4 supported PHP 7.3+. The new SDK requires PHP 8.2 or newer. + +### Runtime dependencies changed + +- `guzzlehttp/guzzle:^7.0` is now required. +- `paragonie/halite` was upgraded from `^4.0` to `^5.1`. +- `ext-curl` is now declared as `^8.2`. + +If your app or deployment environment was pinned to older PHP or extension versions, upgrade those first. + +--- + +## Biggest Conceptual Changes + +### 1. The SDK now revolves around an instantiated client + +Before: + +```php +use WorkOS\WorkOS; +use WorkOS\UserManagement; + +WorkOS::setApiKey('sk_test_...'); +WorkOS::setClientId('client_...'); + +$userManagement = new UserManagement(); +$user = $userManagement->createUser('user@example.com'); +``` + +After: + +```php +use WorkOS\WorkOS; + +$workos = new WorkOS( + apiKey: 'sk_test_...', + clientId: 'client_...', +); + +$user = $workos->userManagement()->createUsers( + email: 'user@example.com', +); +``` + +`WorkOS::setApiKey()` and `WorkOS::setClientId()` still exist as defaults, but the intended integration style is now an instantiated client. + +Static getters are no longer the primary configuration path. In v4, `WorkOS::getApiKey()` and `WorkOS::getClientId()` loaded environment variables and threw when unset; in v5, they are nullable compatibility shims, and credential validation happens when an operation requires them. + +### 2. Most product areas are now accessed through the `WorkOS` client + +Instead of instantiating `new SSO()`, `new UserManagement()`, `new MFA()`, and so on, you now call lazy client methods: + +- `$workos->sso()` +- `$workos->userManagement()` +- `$workos->multiFactorAuth()` +- `$workos->directorySync()` +- `$workos->organizations()` +- `$workos->authorization()` +- `$workos->adminPortal()` +- `$workos->auditLogs()` +- `$workos->featureFlags()` +- `$workos->webhooks()` + +### 3. The SDK is now typed and generated + +Resources are now typed `readonly` models with `fromArray()` / `toArray()` methods. Timestamps are commonly hydrated into `DateTimeImmutable`, and many option values now use enums instead of free-form strings. + +If you previously relied on mutable resource objects, dynamic properties, or `BaseWorkOSResource`, review that code carefully. + +### 4. Named arguments are strongly recommended + +Many generated methods now have longer signatures with optional parameters near the front. Positional argument code that compiled in v4 will often call the wrong parameter in v5. + +Prefer named arguments: + +```php +$workos->organizations()->listOrganizations( + after: 'org_123', + limit: 25, +); +``` + +--- + +## Breaking Changes by Area + +### Client bootstrap and transport + +#### Direct class construction is no longer the default integration pattern + +Most APIs now live behind the `WorkOS` client and share an internal `HttpClient`, so code like this should be removed: + +```php +new \WorkOS\SSO(); +new \WorkOS\UserManagement(); +new \WorkOS\Organizations(); +new \WorkOS\MFA(); +new \WorkOS\Portal(); +new \WorkOS\RBAC(); +``` + +Use the `WorkOS` client methods instead. + +#### Imports and type hints also need to move to the new surface + +It is not enough to replace `new \WorkOS\SSO()` with `$workos->sso()`. If your code imported or type-hinted old top-level service classes such as `WorkOS\UserManagement`, `WorkOS\Portal`, or `WorkOS\RBAC`, update those references to the client-accessed services instead. + +#### `Client`, `RequestClientInterface`, and `CurlRequestClient` were removed + +If you were customizing transport internals with: + +- `Client::setRequestClient(...)` +- `Client::requestClient()` +- `RequestClientInterface` +- `CurlRequestClient` + +switch to the new Guzzle-based runtime. The supported customization points are: + +- `new WorkOS(..., handler: $handlerStack)` +- per-request `RequestOptions` + +#### Several static `WorkOS` configuration methods were removed + +These v4 methods are gone: + +- `WorkOS::getApiBaseURL()` +- `WorkOS::setApiBaseUrl()` +- `WorkOS::setIdentifier()` +- `WorkOS::getIdentifier()` +- `WorkOS::setVersion()` +- `WorkOS::getVersion()` + +Configure `baseUrl`, `timeout`, `maxRetries`, and `handler` via the `WorkOS` constructor instead. + +#### `WorkOS::getApiKey()` and `WorkOS::getClientId()` no longer validate configuration + +Before: + +```php +use WorkOS\WorkOS; + +WorkOS::setApiKey(getenv('WORKOS_API_KEY')); +WorkOS::setClientId(getenv('WORKOS_CLIENT_ID')); + +$clientId = WorkOS::getClientId(); +$apiKey = WorkOS::getApiKey(); +``` + +After: + +```php +use WorkOS\WorkOS; + +$workos = new WorkOS( + apiKey: getenv('WORKOS_API_KEY'), + clientId: getenv('WORKOS_CLIENT_ID'), +); +``` + +In v4, the getters loaded env vars and threw `ConfigurationException` when missing. In v5, they only return the current static shim value. If you used them as bootstrap-time validation, move that validation to `new WorkOS(...)` or to the first API call that requires credentials. + +### Pagination and list responses + +#### `Resource\PaginatedResource` was replaced with `WorkOS\PaginatedResponse` + +Before: + +```php +[$before, $after, $users] = $userManagement->listUsers(); +``` + +After: + +```php +$page = $workos->userManagement()->listUsers(); + +$users = $page->data; +$after = $page->listMetadata['after'] ?? null; +``` + +`PaginatedResponse` also adds auto-pagination helpers: + +```php +foreach ($page->autoPagingIterator() as $user) { + // ... +} +``` + +Auto-pagination only follows `after` cursors. If your integration previously relied on reverse pagination with `before`, keep fetching those pages manually. + +#### Array destructuring and magic list keys should be considered removed + +v4 list responses supported access patterns like: + +- `[$before, $after, $items] = $result` +- `$result->users` +- `$result->organizations` + +In v5, use: + +- `$result->data` +- `$result->listMetadata` +- `$result->hasMore()` + +### Resources and exceptions + +#### `BaseWorkOSResource` is gone + +These v4 behaviors are no longer part of the resource model: + +- `BaseWorkOSResource` +- `constructFromResponse()` +- mutable dynamic properties +- the `raw` response bag on every resource + +If you previously accessed `$resource->raw`, mutated resource fields, or extended resource base classes, migrate to typed properties plus `toArray()`. + +#### Resource field types are stricter + +Examples of behavior changes you may notice: + +- timestamps are often `DateTimeImmutable` instead of strings +- enums are used for many option and state fields +- list responses sometimes return typed wrappers like `RoleList` or `ListModel` + +Common constant-to-enum migrations include: + +```php +use WorkOS\Resource\EventsOrder; + +$workos->organizations()->listOrganizations( + order: EventsOrder::Asc, +); +``` + +```php +use WorkOS\Resource\ConnectionsConnectionType; + +$workos->sso()->listConnections( + connectionType: ConnectionsConnectionType::OktaSAML, +); +``` + +#### Exception types are more granular + +The new runtime maps HTTP failures to explicit exception classes such as: + +- `AuthenticationException` +- `AuthorizationException` +- `BadRequestException` +- `ConflictException` +- `ConnectionException` +- `NotFoundException` +- `RateLimitExceededException` +- `ServerException` +- `TimeoutException` +- `UnprocessableEntityException` + +These exceptions now expose request metadata like `statusCode`, `requestId`, and for rate limits, `retryAfter`. + +### SSO + +#### `SSO` is now accessed through the client + +Before: + +```php +$sso = new \WorkOS\SSO(); +``` + +After: + +```php +$sso = $workos->sso(); +``` + +#### `getAuthorizationUrl()` no longer builds a URL locally + +In v4, `SSO::getAuthorizationUrl(...)` returned a string and implicitly used `WorkOS::getClientId()`. + +In v5 it: + +- makes an HTTP request +- returns `WorkOS\Resource\SSOAuthorizeUrlResponse` +- requires an instantiated client with `clientId` +- requires `redirectUri` + +Before: + +```php +$url = $sso->getAuthorizationUrl( + domain: 'example.com', + redirectUri: 'https://example.com/callback', + state: ['return_to' => '/dashboard'], +); +``` + +After: + +```php +$response = $workos->sso()->getAuthorizationUrl( + redirectUri: 'https://example.com/callback', + domain: 'example.com', + state: json_encode(['return_to' => '/dashboard']), +); + +$url = $response->url; +``` + +`state` is now a string parameter. If you used array state in v4, encode it yourself. + +`client_id` now comes from the instantiated `WorkOS` client, and the SDK always sends `response_type=code` for you. + +#### `getProfileAndToken()` now requires explicit credentials + +Before: + +```php +$profile = $sso->getProfileAndToken($code); +``` + +After: + +```php +$result = $workos->sso()->getProfileAndToken( + clientId: 'client_...', + clientSecret: 'sk_test_...', + code: $code, + grantType: 'authorization_code', +); +``` + +#### `getProfile($accessToken)` changed shape + +In v4, `getProfile()` accepted the access token directly. + +In v5, the method signature no longer takes an access token argument. Based on the current API surface, pass the token via `RequestOptions` headers: + +```php +use WorkOS\RequestOptions; + +$profile = $workos->sso()->getProfile( + options: new RequestOptions( + extraHeaders: ['Authorization' => "Bearer {$accessToken}"], + ), +); +``` + +### User Management and sessions + +#### `UserManagement` is now accessed through the client + +Before: + +```php +$userManagement = new \WorkOS\UserManagement(); +``` + +After: + +```php +$userManagement = $workos->userManagement(); +``` + +#### Session helpers moved out of `UserManagement` + +These v4 methods are no longer on `UserManagement`: + +- `getJwksUrl()` +- `authenticateWithSessionCookie()` +- `loadSealedSession()` +- `getSessionFromCookie()` + +Use `SessionManager` instead: + +```php +use WorkOS\SessionManager; + +$url = SessionManager::getJwksUrl('client_...'); + +$result = $workos->sessionManager()->authenticate( + sessionData: $_COOKIE['wos-session'] ?? '', + cookiePassword: $cookiePassword, + clientId: 'client_...', +); +``` + +The old `new UserManagement($encryptor)` customization point was also removed. + +#### Session authentication now returns arrays instead of response models + +Before: + +```php +$result = $userManagement->authenticateWithSessionCookie( + $sealedSession, + $cookiePassword, +); +``` + +After: + +```php +$result = $workos->sessionManager()->authenticate( + sessionData: $sealedSession, + cookiePassword: $cookiePassword, + clientId: 'client_...', +); +``` + +The new method returns an associative array such as `['authenticated' => true, ...]` or `['authenticated' => false, 'reason' => 'invalid_jwt']`. If your code checked for `SessionAuthenticationSuccessResponse` or `SessionAuthenticationFailureResponse`, update that logic. + +#### Auth methods now read credentials from the client instance + +Before: + +```php +$result = $userManagement->authenticateWithPassword( + 'client_...', + 'user@example.com', + 'secret', +); +``` + +After: + +```php +$result = $workos->userManagement()->authenticateWithPassword( + email: 'user@example.com', + password: 'secret', +); +``` + +The same change applies to methods like `authenticateWithCode()` and `authenticateWithRefreshToken()`: remove leading credential arguments and ensure the `WorkOS` client was instantiated with `apiKey` and `clientId`. + +#### Several User Management methods were renamed + +| v4 | v5 | +| ---------------------------------------- | ----------------------------------------------------------- | +| `createUser()` | `userManagement()->createUsers()` | +| `createOrganizationMembership()` | `userManagement()->createOrganizationMemberships()` | +| `sendInvitation()` | `userManagement()->createInvitations()` | +| `findInvitationByToken()` | `userManagement()->getByToken()` | +| `authenticateWithSelectedOrganization()` | `userManagement()->authenticateWithOrganizationSelection()` | +| `verifyEmail()` | `userManagement()->confirmEmailVerification()` | +| `resetPassword()` | `userManagement()->confirmPasswordReset()` | +| `listSessions()` | `userManagement()->listUserSessions()` | + +#### Deprecated methods were removed + +These methods existed in v4 but should be treated as removed in v5: + +- `sendPasswordResetEmail()` -> use `createPasswordReset()` +- `sendMagicAuthCode()` -> use `createMagicAuth()` + +#### Auth and logout URL helpers changed behavior + +`userManagement()->getAuthorizationUrl()` and `userManagement()->getLogoutUrl()` no longer just build a local string. + +Notable differences: + +- they make API calls +- `getAuthorizationUrl()` now requires `redirectUri` and an instantiated client with `clientId` +- `state` is now a string, not an array that the SDK JSON-encodes for you +- `getLogoutUrl()` now returns response data instead of a locally composed URL string + +Before: + +```php +$url = $userManagement->getAuthorizationUrl( + 'https://example.com/callback', + ['return_to' => '/dashboard'], + WorkOS\UserManagement::AUTHORIZATION_PROVIDER_AUTHKIT, +); +``` + +After: + +```php +$response = $workos->userManagement()->getAuthorizationUrl( + redirectUri: 'https://example.com/callback', + state: json_encode(['return_to' => '/dashboard']), + provider: \WorkOS\Resource\UserManagementAuthenticationProvider::Authkit, +); +``` + +### Directory Sync + +#### `DirectorySync` method names are more explicit + +| v4 | v5 | +| -------------- | ---------------------------------------- | +| `listGroups()` | `directorySync()->listDirectoryGroups()` | +| `getGroup()` | `directorySync()->getDirectoryGroup()` | +| `listUsers()` | `directorySync()->listDirectoryUsers()` | +| `getUser()` | `directorySync()->getDirectoryUser()` | + +The API also moved from direct construction to `$workos->directorySync()`. + +### MFA + +#### `MFA` became `multiFactorAuth()` + +Before: + +```php +$mfa = new \WorkOS\MFA(); +``` + +After: + +```php +$mfa = $workos->multiFactorAuth(); +``` + +#### `verifyFactor()` is gone + +Use `verifyChallenge()`: + +```php +$result = $workos->multiFactorAuth()->verifyChallenge( + id: $authenticationChallengeId, + code: '123456', +); +``` + +#### User-scoped MFA APIs moved here from `UserManagement` + +| v4 | v5 | +| -------------------- | -------------------------------------------- | +| `enrollAuthFactor()` | `multiFactorAuth()->createUserAuthFactors()` | +| `listAuthFactors()` | `multiFactorAuth()->listUserAuthFactors()` | + +### Organizations, Admin Portal, Feature Flags, and Authorization + +#### `Portal` became `adminPortal()` + +Before: + +```php +$portal = new \WorkOS\Portal(); +$link = $portal->generateLink('org_123', 'sso'); +``` + +After: + +```php +$response = $workos->adminPortal()->generateLink( + organization: 'org_123', + intent: \WorkOS\Resource\GenerateLinkIntent::SSO, +); + +$link = $response->link; +``` + +`intent_options` is also now supported. + +#### `RBAC` was replaced by `authorization()` + +Before: + +```php +$rbac = new \WorkOS\RBAC(); +``` + +After: + +```php +$authorization = $workos->authorization(); +``` + +The environment-role method names were renamed: + +| v4 | v5 | +| --------------------------------- | ------------------------------------------ | +| `createEnvironmentRole()` | `authorization()->createRoles()` | +| `listEnvironmentRoles()` | `authorization()->listRoles()` | +| `getEnvironmentRole()` | `authorization()->getRole()` | +| `updateEnvironmentRole()` | `authorization()->updateRole()` | +| `setEnvironmentRolePermissions()` | `authorization()->updateRolePermissions()` | +| `addEnvironmentRolePermission()` | `authorization()->createRolePermissions()` | + +Organization-role APIs also moved from `Organizations` / `RBAC` into `authorization()`. + +#### Feature flag APIs moved out of `Organizations` + +If you used: + +- `Organizations::listOrganizationFeatureFlags()` + +switch to: + +- `$workos->featureFlags()->listOrganizationFeatureFlags(...)` + +#### Some idempotency keys moved into `RequestOptions` + +Before: + +```php +$organizations = new \WorkOS\Organizations(); + +$organization = $organizations->createOrganization('Acme', null, null, 'idemp_123'); +``` + +After: + +```php +use WorkOS\RequestOptions; + +$organization = $workos->organizations()->createOrganizations( + name: 'Acme', + options: new RequestOptions( + idempotencyKey: 'idemp_123', + ), +); +``` + +The same pattern applies anywhere the new runtime uses `RequestOptions`. + +If you rely on retries for write requests, set an explicit idempotency key yourself. The new runtime retries retryable responses, but it does not auto-generate idempotency keys for POST requests. + +### Audit Logs + +#### `AuditLogs` is now accessed through the client, and several methods were renamed + +| v4 | v5 | +| ---------------- | ------------------------------------ | +| `createEvent()` | `auditLogs()->createEvents()` | +| `createExport()` | `auditLogs()->createExports()` | +| `createSchema()` | `auditLogs()->createActionSchemas()` | +| `schemaExists()` | removed | + +There is no direct `schemaExists()` helper in v5. Call `listActionSchemas()` and handle `NotFoundException` if you need equivalent behavior. + +### Passwordless + +#### `Passwordless::createSession()` changed signature + +The old positional signature was: + +```php +createSession($email, $redirectUri, $state, $type, $connection, $expiresIn) +``` + +The new signature is: + +```php +$workos->passwordless()->createSession( + email: 'user@example.com', + type: 'MagicLink', + redirectUri: 'https://example.com/callback', + state: '...', + expiresIn: 900, +); +``` + +Notable changes: + +- `connection` is no longer an argument +- the parameter order changed completely +- the method now returns an array instead of a `PasswordlessSession` resource + +#### `sendSession()` now takes a session ID string + +Before: + +```php +$session = $passwordless->createSession(...); +$passwordless->sendSession($session); +``` + +After: + +```php +$session = $workos->passwordless()->createSession(...); +$workos->passwordless()->sendSession($session['id']); +``` + +### Widgets + +`Widgets::getToken()` was renamed to `widgets()->createToken()`, and the return type is now `WidgetSessionTokenResponse`. + +### Vault + +The Vault API was expanded and renamed around "objects" instead of "vault objects". + +| v4 | v5 | +| -------------------- | ------------------------ | +| `getVaultObject()` | `vault()->readObject()` | +| `listVaultObjects()` | `vault()->listObjects()` | + +Additional Vault capabilities were added in v5, including object version listing, object creation/update/delete, data-key APIs, and local encrypt/decrypt helpers. + +### Webhooks + +#### Webhook CRUD and verification are now separate concerns + +v4 used a single `Webhook` helper for verification. + +In v5: + +- `$workos->webhooks()` manages webhook endpoints +- `$workos->webhookVerification()` verifies webhook payloads + +#### Verification now throws instead of returning error strings + +Before: + +```php +$webhook = new \WorkOS\Webhook(); +$result = $webhook->verifyHeader($sigHeader, $payload, $secret, 180); + +if ($result !== 'pass') { + // handle string error +} +``` + +After: + +```php +$event = $workos->webhookVerification()->verifyEvent( + eventBody: $payload, + eventSignature: $sigHeader, + secret: $secret, +); +``` + +If verification fails, `verifyHeader()` / `verifyEvent()` throw `InvalidArgumentException`. + +--- + +## New Features and Additions + +These are not migration blockers, but they are new capabilities in the v5 SDK: + +- `apiKeys()` for organization API key management and validation. +- `connect()` for Connect applications and OAuth completion. +- `events()` for event listing. +- `featureFlags()` for feature flag retrieval and targeting. +- `organizationDomains()` for standalone organization domain operations. +- `pipes()` for data integration flows. +- `radar()` for attempts and list management. +- `actions()` for WorkOS Actions signature verification and signed responses. +- `sessionManager()` for sealing, unsealing, session-cookie auth, JWKS helpers, and refresh flows. +- `pkce()` for PKCE verifier/challenge generation and AuthKit/SSO PKCE flows. +- expanded `vault()` support for object CRUD, data keys, and local encryption helpers. +- `RequestOptions` for per-request headers, idempotency keys, base URL overrides, timeout overrides, and retry overrides. +- automatic retries for `429` and common `5xx` responses. +- `PaginatedResponse::autoPagingIterator()` for iterating across all pages. + +--- + +## Testing Your Migration + +After migrating, verify at least the following: + +1. PHP runtime is 8.2+ everywhere the SDK executes. +2. All direct `new WorkOS\...` class construction has been replaced with a `WorkOS` client. +3. Any list-response destructuring has been updated to `PaginatedResponse`. +4. Any code that accessed resource `raw` data or mutated resource objects has been updated. +5. Any code that relied on `WorkOS::getApiKey()` / `getClientId()` throwing during bootstrap has been updated. +6. SSO and User Management URL-generation code has been updated for the new request/response shape. +7. Session-cookie code now uses `SessionManager`, and any success/failure type checks were updated for the new array return shape. +8. Deprecated User Management and MFA method names have been replaced, including auth methods that no longer accept leading credential arguments. +9. Webhook verification paths were updated to exception-based handling. +10. Integration tests for SSO, AuthKit, invitations, password reset, and webhooks still pass. diff --git a/lib/Actions.php b/lib/Actions.php new file mode 100644 index 00000000..e77759c1 --- /dev/null +++ b/lib/Actions.php @@ -0,0 +1,128 @@ + 'authentication_action_response', + 'user_registration' => 'user_registration_action_response', + ]; + + /** + * @param HttpClient $client Reserved for future use (e.g. server-side action endpoints). + */ + public function __construct( + private readonly HttpClient $client, // @phpstan-ignore property.onlyWritten + ) { + } + + /** + * Verify the signature of an Actions request. + * + * @param string $payload The raw Actions request body. + * @param string $sigHeader The signature header value. + * @param string $secret The Actions secret. + * @param int $tolerance Seconds the event is valid for. Defaults to 30. + * @throws \InvalidArgumentException If the signature cannot be verified. + */ + public function verifyHeader( + string $payload, + string $sigHeader, + string $secret, + int $tolerance = self::DEFAULT_TOLERANCE, + ): void { + $parts = explode(', ', $sigHeader); + if (count($parts) !== 2) { + throw new \InvalidArgumentException( + 'Unable to extract timestamp and signature hash from header' + ); + } + + $issuedTimestamp = substr($parts[0], 2); // strip "t=" + $signatureHash = substr($parts[1], 3); // strip "v1=" + + $currentTime = time(); + $timestampInSeconds = intval($issuedTimestamp) / 1000; + $secondsSinceIssued = $currentTime - $timestampInSeconds; + + if ($secondsSinceIssued > $tolerance) { + throw new \InvalidArgumentException('Timestamp outside the tolerance zone'); + } + + $expectedSignature = hash_hmac('sha256', "{$issuedTimestamp}.{$payload}", $secret); + + if (!hash_equals($expectedSignature, $signatureHash)) { + throw new \InvalidArgumentException( + 'Signature hash does not match the expected signature hash for payload' + ); + } + } + + /** + * Verify and deserialize an Actions request payload. + * + * @param string $payload The raw Actions request body. + * @param string $sigHeader The signature header value. + * @param string $secret The Actions secret. + * @param int $tolerance Seconds the event is valid for. Defaults to 30. + * @return array The deserialized action payload. + * @throws \InvalidArgumentException If the signature cannot be verified. + */ + public function constructAction( + string $payload, + string $sigHeader, + string $secret, + int $tolerance = self::DEFAULT_TOLERANCE, + ): array { + $this->verifyHeader($payload, $sigHeader, $secret, $tolerance); + return json_decode($payload, true); + } + + /** + * Build and sign an Actions response. + * + * @param string $actionType 'authentication' or 'user_registration'. + * @param string $verdict 'Allow' or 'Deny'. + * @param string|null $errorMessage Optional error message for Deny verdicts. + * @param string $secret The Actions secret. + * @return array The signed response payload. + */ + public function signResponse( + string $actionType, + string $verdict, + string $secret, + ?string $errorMessage = null, + ): array { + $timestamp = (int) (microtime(true) * 1000); + + $responsePayload = [ + 'timestamp' => $timestamp, + 'verdict' => $verdict, + ]; + if ($errorMessage !== null) { + $responsePayload['error_message'] = $errorMessage; + } + + $payloadJson = json_encode($responsePayload, JSON_UNESCAPED_SLASHES); + $signedPayload = "{$timestamp}.{$payloadJson}"; + $signature = hash_hmac('sha256', $signedPayload, $secret); + $objectType = self::ACTION_TYPE_TO_RESPONSE_OBJECT[$actionType] + ?? throw new \InvalidArgumentException("Unknown action type: {$actionType}"); + + return [ + 'object' => $objectType, + 'payload' => $responsePayload, + 'signature' => $signature, + ]; + } +} diff --git a/lib/AuditLogs.php b/lib/AuditLogs.php deleted file mode 100644 index 65d7c125..00000000 --- a/lib/AuditLogs.php +++ /dev/null @@ -1,224 +0,0 @@ - $organizationId, - "event" => $event - ]; - - $headers = [ - "idempotency_key" => $idempotencyKey - ]; - - $response = Client::request(Client::METHOD_POST, $eventsPath, $headers, $params, true); - - return Resource\AuditLogCreateEventStatus::constructFromResponse($response); - } - - /** - * @param array $auditLogExportOptions Associative array containing the keys detailed below - * @var null|string $organizationId Description of the record. - * @var null|string $rangeStart ISO-8601 Timestamp of the start of Export's the date range. - * @var null|string $rangeEnd ISO-8601 Timestamp of the end of Export's the date range. - * @var null|array $actions Actions that Audit Log Events will be filtered by. - * @var null|array $actors Actor names that Audit Log Events will be filtered by. @deprecated 3.3.0 Use $actorNames instead. This method will be removed in a future major version. - * @var null|array $targets Target types that Audit Log Events will be filtered by. - * @var null|array $actorNames Actor names that Audit Log Events will be filtered by. - * @var null|array $actorIds Actor IDs that Audit Log Events will be filtered by. - * - * @throws Exception\WorkOSException - * - * @return Resource\AuditLogExport - */ - - public function createExport($organizationId, $rangeStart, $rangeEnd, ?array $actions = null, ?array $actors = null, ?array $targets = null, ?array $actorNames = null, ?array $actorIds = null) - { - $createExportPath = "audit_logs/exports"; - - $params = [ - "organization_id" => $organizationId, - "range_end" => $rangeEnd, - "range_start" => $rangeStart - ]; - - if (!is_null($actions)) { - $params["actions"] = $actions; - }; - - if (!is_null($actors)) { - $msg = "'actors' is deprecated. Please use 'actorNames' instead'"; - - error_log($msg); - - $params["actors"] = $actors; - }; - - if (!is_null($actorNames)) { - $params["actor_names"] = $actorNames; - }; - - if (!is_null($actorIds)) { - $params["actor_ids"] = $actorIds; - }; - - if (!is_null($targets)) { - $params["targets"] = $targets; - }; - - $response = Client::request(Client::METHOD_POST, $createExportPath, null, $params, true); - return Resource\AuditLogExport::constructFromResponse($response); - } - - /** - * @param string $auditLogExportId Unique identifier of the Audit Log Export - * - * @throws Exception\WorkOSException - * @throws \InvalidArgumentException - * - * @return Resource\AuditLogExport - */ - public function getExport($auditLogExportId) - { - // Validate export ID parameter to prevent path traversal - if (!is_string($auditLogExportId) || !preg_match('/^[a-zA-Z0-9._-]+$/', $auditLogExportId)) { - throw new \InvalidArgumentException('Invalid export ID format. Export ID must be a string containing only alphanumeric characters, dots, underscores, and hyphens.'); - } - - $getExportPath = "audit_logs/exports/{$auditLogExportId}"; - - $response = Client::request(Client::METHOD_GET, $getExportPath, null, null, true); - - return Resource\AuditLogExport::constructFromResponse($response); - } - - /** - * Create an audit log action schema. - * - * @param string $action The action name for the schema - * @param array $schema Array containing the schema definition - * - * @throws Exception\WorkOSException - * @throws \InvalidArgumentException - * - * @return array The created schema response - */ - public function createSchema($action, $schema) - { - // Validate action parameter to prevent path traversal - if (!is_string($action) || !preg_match('/^[a-zA-Z0-9._-]+$/', $action)) { - throw new \InvalidArgumentException('Invalid action format. Action must be a string containing only alphanumeric characters, dots, underscores, and hyphens.'); - } - - $schemaPath = "audit_logs/actions/{$action}/schemas"; - - $response = Client::request(Client::METHOD_POST, $schemaPath, null, $schema, true); - - return $response; - } - - /** - * Check if an audit log action schema exists. - * - * @param string $action The action name to check - * - * @throws Exception\WorkOSException - * @throws \InvalidArgumentException - * - * @return bool True if schema exists, false if not found - */ - public function schemaExists($action) - { - // Validate action parameter to prevent path traversal - if (!is_string($action) || !preg_match('/^[a-zA-Z0-9._-]+$/', $action)) { - throw new \InvalidArgumentException('Invalid action format. Action must be a string containing only alphanumeric characters, dots, underscores, and hyphens.'); - } - - $schemaPath = "audit_logs/actions/{$action}/schemas"; - - try { - Client::request(Client::METHOD_GET, $schemaPath, null, null, true); - return true; - } catch (Exception\NotFoundException $e) { - return false; - } - } - - /** - * List all registered audit log actions. - * - * @param int $limit Maximum number of actions to return (default: 100) - * @param null|string $before Action ID to look before - * @param null|string $after Action ID to look after - * @param null|string $order The order in which to paginate records ("asc" or "desc") - * - * @throws Exception\WorkOSException - * - * @return array Array of registered actions - */ - public function listActions($limit = 100, $before = null, $after = null, $order = null) - { - $actionsPath = "audit_logs/actions"; - - $params = [ - "limit" => $limit - ]; - - if ($before !== null) { - $params["before"] = $before; - } - - if ($after !== null) { - $params["after"] = $after; - } - - if ($order !== null) { - $params["order"] = $order; - } - - $response = Client::request(Client::METHOD_GET, $actionsPath, null, $params, true); - - return $response; - } -} diff --git a/lib/Client.php b/lib/Client.php deleted file mode 100644 index 28adf4a9..00000000 --- a/lib/Client.php +++ /dev/null @@ -1,120 +0,0 @@ - - */ - public static function request($method, $path, ?array $headers = null, ?array $params = null, $withAuth = false) - { - $url = self::generateUrl($path); - - $requestHeaders = self::generateBaseHeaders($withAuth); - if ($headers) { - $requestHeaders = \array_merge($requestHeaders, $headers); - } - - list($result, $responseHeaders, $responseCode) = self::requestClient()->request( - $method, - $url, - $requestHeaders, - $params - ); - $response = new Resource\Response($result, $responseHeaders, $responseCode); - - if ($responseCode >= 400) { - if ($responseCode >= 500) { - throw new Exception\ServerException($response); - } elseif ($responseCode === 401) { - throw new Exception\AuthenticationException($response); - } elseif ($responseCode === 403) { - throw new Exception\AuthorizationException($response); - } elseif ($responseCode === 404) { - throw new Exception\NotFoundException($response); - } - - throw new Exception\BadRequestException($response); - } - - return $response->json(); - } - - /** - * Generate base headers for request. - * - * @param boolean $withAuth return with authorization header if true - * - * @return array - */ - public static function generateBaseHeaders($withAuth = false) - { - $baseHeaders = ["User-Agent: " . WorkOS::getIdentifier() . "/" . WORKOS::getVersion()]; - if ($withAuth) { - \array_push($baseHeaders, "Authorization: Bearer " . WorkOS::getApikey()); - } - - return $baseHeaders; - } - - /** - * Generates a URL to the WorkOS API. - * - * @param string $path Path to the WorkOS resource - * @param null|array $params Associative array to be passed as query parameters - * - * @return string - */ - public static function generateUrl($path, ?array $params = null) - { - $url = WorkOS::getApiBaseUrl() . $path; - - if (is_array($params) && !empty($params)) { - $queryParams = http_build_query($params); - $url .= "?" . $queryParams; - } - - return $url; - } -} diff --git a/lib/CookieSession.php b/lib/CookieSession.php deleted file mode 100644 index 4714c94d..00000000 --- a/lib/CookieSession.php +++ /dev/null @@ -1,149 +0,0 @@ -userManagement = $userManagement; - $this->sealedSession = $sealedSession; - $this->cookiePassword = $cookiePassword; - } - - /** - * Authenticates the sealed session and returns user information. - * - * @return SessionAuthenticationSuccessResponse|SessionAuthenticationFailureResponse - * @throws Exception\WorkOSException - */ - public function authenticate() - { - return $this->userManagement->authenticateWithSessionCookie( - $this->sealedSession, - $this->cookiePassword - ); - } - - /** - * Refreshes an expired session and returns new tokens. - * - * Note: This method returns raw tokens. The calling code (e.g., authkit-php) - * is responsible for sealing the tokens into a new session cookie. - * - * @param array $options Options for session refresh - * - 'organizationId' (string|null): Organization to scope the session to - * - * @return array{SessionAuthenticationSuccessResponse|SessionAuthenticationFailureResponse, array|null} - * Returns [response, newTokens] where newTokens contains: - * - 'access_token': The new access token - * - 'refresh_token': The new refresh token - * - 'session_id': The session ID - * Returns [failureResponse, null] on error. - * @throws Exception\WorkOSException - */ - public function refresh(array $options = []) - { - $organizationId = $options['organizationId'] ?? null; - - // First authenticate to get the current session data - $authResult = $this->authenticate(); - - if (!$authResult->authenticated) { - return [$authResult, null]; - } - - // Tight try/catch for refresh token API call - try { - $refreshedAuth = $this->userManagement->authenticateWithRefreshToken( - WorkOS::getClientId(), - $authResult->refreshToken, - null, - null, - $organizationId - ); - } catch (Exception\BaseRequestException $e) { - $failureResponse = new SessionAuthenticationFailureResponse( - SessionAuthenticationFailureResponse::REASON_HTTP_ERROR - ); - return [$failureResponse, null]; - } - - // Build success response - $successResponse = SessionAuthenticationSuccessResponse::constructFromResponse([ - 'authenticated' => true, - 'access_token' => $refreshedAuth->accessToken, - 'refresh_token' => $refreshedAuth->refreshToken, - 'session_id' => $authResult->sessionId, - 'user' => $refreshedAuth->user->raw, - 'organization_id' => $refreshedAuth->organizationId ?? $organizationId, - 'authentication_method' => $authResult->authenticationMethod - ]); - - // Return raw tokens for the caller to seal - $newTokens = [ - 'access_token' => $refreshedAuth->accessToken, - 'refresh_token' => $refreshedAuth->refreshToken, - 'session_id' => $authResult->sessionId - ]; - - return [$successResponse, $newTokens]; - } - - /** - * Gets the logout URL for the current session. - * - * @param array $options - * - 'returnTo' (string|null): URL to redirect to after logout - * - * @return string Logout URL - * @throws Exception\UnexpectedValueException - */ - public function getLogoutUrl(array $options = []) - { - $authResult = $this->authenticate(); - - if (!$authResult->authenticated) { - throw new Exception\UnexpectedValueException( - "Cannot get logout URL for unauthenticated session" - ); - } - - $returnTo = $options['returnTo'] ?? null; - return $this->userManagement->getLogoutUrl($authResult->sessionId, $returnTo); - } -} diff --git a/lib/DirectorySync.php b/lib/DirectorySync.php deleted file mode 100644 index 003f2afe..00000000 --- a/lib/DirectorySync.php +++ /dev/null @@ -1,248 +0,0 @@ - $dirs] = $result, $result->directories - */ - public function listDirectories( - ?string $domain = null, - ?string $search = null, - $limit = self::DEFAULT_PAGE_SIZE, - ?string $before = null, - ?string $after = null, - ?string $organizationId = null, - ?string $order = null - ) { - $directoriesPath = "directories"; - $params = [ - "limit" => $limit, - "before" => $before, - "after" => $after, - "domain" => $domain, - "search" => $search, - "organization_id" => $organizationId, - "order" => $order - ]; - - $response = Client::request( - Client::METHOD_GET, - $directoriesPath, - null, - $params, - true - ); - - return Resource\PaginatedResource::constructFromResponse($response, Resource\Directory::class, 'directories'); - } - - /** - * List Directory Groups. - * - * @param null|string $directory Directory ID - * @param null|string $user Directory User ID - * @param int $limit Maximum number of records to return - * @param null|string $before Directory Group ID to look before - * @param null|string $after Directory Group ID to look after - * @param Resource\Order $order The Order in which to paginate records - * - * @throws Exception\WorkOSException - * - * @return Resource\PaginatedResource A paginated resource containing before/after cursors and groups array. - * Supports: [$before, $after, $groups] = $result, ["groups" => $groups] = $result, $result->groups - */ - public function listGroups( - ?string $directory = null, - ?string $user = null, - $limit = self::DEFAULT_PAGE_SIZE, - ?string $before = null, - ?string $after = null, - ?string $order = null - ) { - $groupsPath = "directory_groups"; - - $params = [ - "limit" => $limit, - "before" => $before, - "after" => $after, - "order" => $order - ]; - if ($directory) { - $params["directory"] = $directory; - } - if ($user) { - $params["user"] = $user; - } - - $response = Client::request( - Client::METHOD_GET, - $groupsPath, - null, - $params, - true - ); - - return Resource\PaginatedResource::constructFromResponse($response, Resource\DirectoryGroup::class, 'groups'); - } - - /** - * Get a Directory Group. - * - * @param string $directoryGroup Directory Group ID - * - * @throws Exception\WorkOSException - * - * @return Resource\DirectoryGroup - */ - public function getGroup($directoryGroup) - { - $groupPath = "directory_groups/{$directoryGroup}"; - - $response = Client::request( - Client::METHOD_GET, - $groupPath, - null, - null, - true - ); - - return Resource\DirectoryGroup::constructFromResponse($response); - } - - /** - * List Directory Users. - * - * @param null|string $directory Directory ID - * @param null|string $group Directory Group ID - * @param int $limit Maximum number of records to return - * @param null|string $before Directory User ID to look before - * @param null|string $after Directory User ID to look after - * @param Resource\Order $order The Order in which to paginate records - * - * @return Resource\PaginatedResource A paginated resource containing before/after cursors and users array. - * Supports: [$before, $after, $users] = $result, ["users" => $users] = $result, $result->users - * - * @throws Exception\WorkOSException - */ - public function listUsers( - ?string $directory = null, - ?string $group = null, - $limit = self::DEFAULT_PAGE_SIZE, - ?string $before = null, - ?string $after = null, - ?string $order = null - ) { - $usersPath = "directory_users"; - - $params = [ - "limit" => $limit, - "before" => $before, - "after" => $after, - "order" => $order - ]; - if ($directory) { - $params["directory"] = $directory; - } - if ($group) { - $params["group"] = $group; - } - - $response = Client::request( - Client::METHOD_GET, - $usersPath, - null, - $params, - true - ); - - return Resource\PaginatedResource::constructFromResponse($response, Resource\DirectoryUser::class, 'users'); - } - - /** - * Get a Directory User. - * - * @param string $directoryUser Directory User ID - * - * @throws Exception\WorkOSException - * - * @return Resource\DirectoryUser - */ - public function getUser($directoryUser) - { - $userPath = "directory_users/{$directoryUser}"; - - $response = Client::request( - Client::METHOD_GET, - $userPath, - null, - null, - true - ); - - return Resource\DirectoryUser::constructFromResponse($response); - } - - /** - * Delete a Directory. - * - * @param string $directory Directory ID - * - * @throws Exception\WorkOSException - * - * @return Resource\Response - */ - public function deleteDirectory($directory) - { - $directoryPath = "directories/{$directory}"; - - $response = Client::request( - Client::METHOD_DELETE, - $directoryPath, - null, - null, - true - ); - - return $response; - } - - /** - * Get a Directory. - * - * @param string $directory WorkOS directory ID - * - * @throws Exception\WorkOSException - * - * @return Resource\Directory - */ - public function getDirectory($directory) - { - $directoriesPath = "directories/{$directory}"; - - $response = Client::request(Client::METHOD_GET, $directoriesPath, null, null, true); - - return Resource\Directory::constructFromResponse($response); - } -} diff --git a/lib/Exception/ApiException.php b/lib/Exception/ApiException.php new file mode 100644 index 00000000..3f00de93 --- /dev/null +++ b/lib/Exception/ApiException.php @@ -0,0 +1,26 @@ +response = $response; - - $responseJson = $response->json(); +declare(strict_types=1); - if (!empty($responseJson["error"])) { - $this->responseError = $responseJson["error"]; - } - if (!empty($responseJson["error_description"])) { - $this->responseErrorDescription = $responseJson["error_description"]; - } - if (!empty($responseJson["errors"])) { - $this->responseErrors = $responseJson["errors"]; - } - if (!empty($responseJson["code"])) { - $this->responseCode = $responseJson["code"]; - } - if (!empty($responseJson["message"])) { - $this->responseMessage = $responseJson["message"]; - } +// @oagen-ignore-file - $this->filterResponseForException($response); - - if (isset($message)) { - $this->message = $message; - } - } - - private function filterResponseForException($response) - { - try { - $responseBody = $response->body; - - $this->message = $responseBody; - } catch (\Exception $e) { - $this->message = ""; - } +namespace WorkOS\Exception; - if (\array_key_exists("x-request-id", $response->headers)) { - $this->requestId = $response->headers["x-request-id"]; - } - } +class BaseRequestException extends ApiException +{ } diff --git a/lib/Exception/ConfigurationException.php b/lib/Exception/ConfigurationException.php index 71417c67..224f7cda 100644 --- a/lib/Exception/ConfigurationException.php +++ b/lib/Exception/ConfigurationException.php @@ -1,12 +1,11 @@ retryAfter = $retryAfter; + } +} diff --git a/lib/Exception/ServerException.php b/lib/Exception/ServerException.php index 2dae67f7..09aaee5f 100644 --- a/lib/Exception/ServerException.php +++ b/lib/Exception/ServerException.php @@ -1,10 +1,11 @@ client = new Client([ + 'handler' => $handler, + ]); + } + + public function getApiKey(): ?string + { + return $this->apiKey !== '' ? $this->apiKey : null; + } + + public function requireApiKey(): string + { + $apiKey = $this->getApiKey(); + if ($apiKey === null) { + throw new ConfigurationException( + 'This operation requires a WorkOS API key. Provide apiKey when instantiating WorkOS or via WORKOS_API_KEY.', + ); + } + + return $apiKey; + } + + public function getClientId(): ?string + { + return $this->clientId; + } + + public function requireClientId(): string + { + if ($this->clientId === null || $this->clientId === '') { + throw new ConfigurationException( + 'This operation requires a WorkOS client ID. Provide clientId when instantiating WorkOS or via WORKOS_CLIENT_ID.', + ); + } + + return $this->clientId; + } + + public function request( + string $method, + string $path, + ?array $query = null, + ?array $body = null, + ?RequestOptions $options = null, + ): ?array { + $maxRetries = $this->resolveMaxRetries($options); + + for ($attempt = 0; $attempt <= $maxRetries; $attempt++) { + try { + $response = $this->client->request( + $method, + $this->resolveUrl($path, $options), + $this->buildRequestOptions($method, $query, $body, $options), + ); + } catch (ConnectException $e) { + if ($attempt < $maxRetries) { + $this->sleep($attempt); + continue; + } + + throw $this->mapTransportException($e); + } catch (RequestException $e) { + if ($e->hasResponse()) { + $response = $e->getResponse(); + if ($response !== null) { + $statusCode = $response->getStatusCode(); + if (in_array($statusCode, self::RETRY_STATUS_CODES, true) && $attempt < $maxRetries) { + $this->sleep($attempt, $response->getHeaderLine('Retry-After')); + continue; + } + + throw $this->mapApiException($response, $e); + } + } + + if ($attempt < $maxRetries) { + $this->sleep($attempt); + continue; + } + + throw $this->mapTransportException($e); + } + + $statusCode = $response->getStatusCode(); + if (in_array($statusCode, self::RETRY_STATUS_CODES, true) && $attempt < $maxRetries) { + $this->sleep($attempt, $response->getHeaderLine('Retry-After')); + continue; + } + + if ($statusCode >= 400) { + throw $this->mapApiException($response); + } + + return $this->decodeResponse($response); + } + + throw new ConnectionException('Request failed after exhausting retries.'); + } + + public function requestPage( + string $method, + string $path, + ?array $query = null, + ?array $body = null, + ?string $modelClass = null, + ?RequestOptions $options = null, + ): PaginatedResponse { + $response = $this->request($method, $path, $query, $body, $options) ?? []; + + return PaginatedResponse::fromArray( + $response, + $modelClass, + function (array $cursorParams) use ($method, $path, $query, $body, $modelClass, $options): PaginatedResponse { + $nextQuery = array_filter( + array_merge($query ?? [], $cursorParams), + fn ($value) => $value !== null, + ); + + return $this->requestPage( + $method, + $path, + $nextQuery, + $body, + $modelClass, + $options, + ); + }, + ); + } + + private function buildRequestOptions( + string $method, + ?array $query, + ?array $body, + ?RequestOptions $options, + ): array { + $headers = [ + 'Content-Type' => 'application/json', + ]; + + if ($this->getApiKey() !== null) { + $headers['Authorization'] = sprintf('Bearer %s', $this->requireApiKey()); + } + + if ($options?->extraHeaders !== null) { + $headers = array_merge($headers, $options->extraHeaders); + } + + if ($options?->idempotencyKey !== null) { + $headers['Idempotency-Key'] = $options->idempotencyKey; + } + + $requestOptions = [ + 'headers' => $headers, + 'http_errors' => false, + 'timeout' => $this->resolveTimeout($options), + ]; + + if ($query !== null) { + $requestOptions['query'] = $query; + } + + if ($body !== null) { + $requestOptions['json'] = $body; + } + + return $requestOptions; + } + + private function resolveUrl(string $path, ?RequestOptions $options): string + { + if (preg_match('#^https?://#i', $path) === 1) { + return $path; + } + + $baseUrl = $options !== null && $options->baseUrl !== null ? $options->baseUrl : $this->baseUrl; + $baseUrl = rtrim($baseUrl, '/'); + return $baseUrl . '/' . ltrim($path, '/'); + } + + private function resolveTimeout(?RequestOptions $options): int + { + return $options !== null && $options->timeout !== null ? $options->timeout : $this->timeout; + } + + private function resolveMaxRetries(?RequestOptions $options): int + { + return $options !== null && $options->maxRetries !== null ? $options->maxRetries : $this->maxRetries; + } + + private function decodeResponse(ResponseInterface $response): ?array + { + if ($response->getStatusCode() === 204) { + return null; + } + + $contents = $response->getBody()->getContents(); + if ($contents === '') { + return null; + } + + $decoded = json_decode($contents, true); + return is_array($decoded) ? $decoded : null; + } + + private function mapApiException(ResponseInterface $response, ?\Throwable $previous = null): ApiException + { + $statusCode = $response->getStatusCode(); + $requestId = $response->getHeaderLine('X-Request-ID') ?: $response->getHeaderLine('x-request-id') ?: null; + $body = $this->decodeErrorBody($response); + + return match ($statusCode) { + 400 => new BadRequestException($body['message'], $statusCode, $requestId, $previous), + 401 => new AuthenticationException($body['message'], $statusCode, $requestId, $previous), + 403 => new AuthorizationException($body['message'], $statusCode, $requestId, $previous), + 404 => new NotFoundException($body['message'], $statusCode, $requestId, $previous), + 409 => new ConflictException($body['message'], $statusCode, $requestId, $previous), + 422 => new UnprocessableEntityException($body['message'], $statusCode, $requestId, $previous), + 429 => new RateLimitExceededException( + $body['message'], + $statusCode, + $requestId, + $previous, + $this->parseRetryAfter($response->getHeaderLine('Retry-After')), + ), + 500, 502, 503, 504 => new ServerException($body['message'], $statusCode, $requestId, $previous), + default => new BaseRequestException($body['message'], $statusCode, $requestId, $previous), + }; + } + + /** + * @return array{message: string} + */ + private function decodeErrorBody(ResponseInterface $response): array + { + $contents = (string) $response->getBody(); + if ($contents === '') { + return ['message' => sprintf('WorkOS request failed with status %d.', $response->getStatusCode())]; + } + + $decoded = json_decode($contents, true); + if (is_array($decoded)) { + $message = $decoded['message'] ?? $decoded['error_description'] ?? $decoded['error'] ?? null; + if (is_string($message) && $message !== '') { + return ['message' => $message]; + } + } + + return ['message' => $contents]; + } + + private function mapTransportException(\Throwable $exception): \Exception + { + if ($this->isTimeoutException($exception)) { + return new TimeoutException(sprintf('Request timed out: %s', $exception->getMessage()), 0, $exception); + } + + return new ConnectionException(sprintf('Connection failed: %s', $exception->getMessage()), 0, $exception); + } + + private function isTimeoutException(\Throwable $exception): bool + { + if ($exception instanceof ConnectException || $exception instanceof RequestException) { + $errno = $exception->getHandlerContext()['errno'] ?? null; + if ($errno === 28) { + return true; + } + } + + return str_contains(strtolower($exception->getMessage()), 'timed out'); + } + + private function parseRetryAfter(?string $retryAfter): ?int + { + if ($retryAfter === null || trim($retryAfter) === '') { + return null; + } + + if (is_numeric($retryAfter)) { + return max(0, (int) $retryAfter); + } + + $timestamp = strtotime($retryAfter); + if ($timestamp === false) { + return null; + } + + return max(0, $timestamp - time()); + } + + private function sleep(int $attempt, ?string $retryAfter = null): void + { + $retryAfterSeconds = $this->parseRetryAfter($retryAfter); + if ($retryAfterSeconds !== null) { + usleep($retryAfterSeconds * 1000000); + return; + } + + $delay = min((2 ** $attempt) * 1000, 30000); + $jitter = random_int(0, (int) ($delay * 0.1)); + usleep(($delay + $jitter) * 1000); + } +} diff --git a/lib/MFA.php b/lib/MFA.php deleted file mode 100644 index 5f653721..00000000 --- a/lib/MFA.php +++ /dev/null @@ -1,222 +0,0 @@ - $type, - "totp_issuer" => $totpIssuer, - "totp_user" => $totpUser, - "phone_number" => $phoneNumber - ]; - $response = Client::request( - Client::METHOD_POST, - $enrollPath, - null, - $params, - true - ); - - if ($type == "totp") { - return Resource\AuthenticationFactorTotp::constructFromResponse($response); - } elseif ($type == "sms") { - return Resource\AuthenticationFactorSms::constructFromResponse($response); - } - } - - - /** - * Initiates the authentication process (a challenge) for an authentication factor - * - * @param string $authenticationFactorId - ID of the authentication factor - * @param string|null $smsTemplate - Optional parameter to customize the message for sms type factors. Must include "{{code}}" if used. - * - * @return Resource\AuthenticationChallengeTotp|Resource\AuthenticationChallengeSms - */ - public function challengeFactor( - $authenticationFactorId, - ?string $smsTemplate = null - ) { - if (!isset($authenticationFactorId)) { - $msg = "Incomplete arguments: 'authentication_factor_id' is a required parameter"; - throw new Exception\UnexpectedValueException($msg); - } - - $challengePath = "auth/factors/{$authenticationFactorId}/challenge"; - - $params = [ - "sms_template" => $smsTemplate - ]; - - $response = Client::request( - Client::METHOD_POST, - $challengePath, - null, - $params, - true - ); - if (isset($response['expires_at'])) { - return Resource\AuthenticationChallengeSms::constructFromResponse($response); - } else { - return Resource\AuthenticationChallengeTotp::constructFromResponse($response); - } - } - - - /** - * @deprecated 1.12.0 Use `verifyChallenge` instead. This method will be removed in a future major version. - * Verifies the one time password provided by the end-user. - * - * @param string $authenticationChallengeId - The ID of the authentication challenge that provided the user the verification code. - * @param string $code - The verification code sent to and provided by the end user. - */ - - public function verifyFactor( - $authenticationChallengeId, - $code - ) { - if (!isset($authenticationChallengeId) || !isset($code)) { - $msg = "Incomplete arguments: 'authenticationChallengeId' and 'code' are required parameters"; - throw new Exception\UnexpectedValueException($msg); - } - - $msg = "'verifyFactor' is deprecated. Please use 'verifyChallenge' instead"; - - error_log($msg); - - $response = (new \WorkOS\MFA()) - ->verifyChallenge( - $authenticationChallengeId, - $code - ); - - return $response; - } - - - /** - * Verifies the one time password provided by the end-user. - * - * @param string $authenticationChallengeId - The ID of the authentication challenge that provided the user the verification code. - * @param string $code - The verification code sent to and provided by the end user. - * - * @throws Exception\WorkOSException - */ - public function verifyChallenge( - $authenticationChallengeId, - $code - ) { - if (!isset($authenticationChallengeId) || !isset($code)) { - $msg = "Incomplete arguments: 'authenticationChallengeId' and 'code' are required parameters"; - throw new Exception\UnexpectedValueException($msg); - } - - $verifyPath = "auth/challenges/{$authenticationChallengeId}/verify"; - - $params = [ - "code" => $code - ]; - - $response = Client::request( - Client::METHOD_POST, - $verifyPath, - null, - $params, - true - ); - - return Resource\VerificationChallenge::constructFromResponse($response); - } - - - /** - * Returns a Factor. - * - * @param string $authenticationFactorId - WorkOS Factor ID - * - * @throws Exception\WorkOSException - */ - public function getFactor($authenticationFactorId) - { - $getFactorPath = "auth/factors/{$authenticationFactorId}"; - - $response = Client::request( - Client::METHOD_GET, - $getFactorPath, - null, - null, - true - ); - - return Resource\AuthenticationFactorTotp::constructFromResponse($response); - } - - - /** - * Deletes a Factor. - * - * @param string $authenticationFactorId - WorkOS Factor ID - * - * @return Resource\Response - * - * @throws Exception\WorkOSException - */ - public function deleteFactor($authenticationFactorId) - { - $deleteFactorPath = "auth/factors/{$authenticationFactorId}"; - - $response = Client::request( - Client::METHOD_DELETE, - $deleteFactorPath, - null, - null, - true - ); - - return $response; - } -} diff --git a/lib/Organizations.php b/lib/Organizations.php deleted file mode 100644 index a0058db1..00000000 --- a/lib/Organizations.php +++ /dev/null @@ -1,288 +0,0 @@ - $orgs] = $result, $result->organizations - * - * @throws Exception\WorkOSException - */ - public function listOrganizations( - ?array $domains = null, - $limit = self::DEFAULT_PAGE_SIZE, - ?string $before = null, - ?string $after = null, - ?string $order = null - ) { - $organizationsPath = "organizations"; - $params = [ - "limit" => $limit, - "before" => $before, - "after" => $after, - "domains" => $domains, - "order" => $order - ]; - - $response = Client::request( - Client::METHOD_GET, - $organizationsPath, - null, - $params, - true - ); - - return Resource\PaginatedResource::constructFromResponse($response, Resource\Organization::class, 'organizations'); - } - - /** - * Create Organization. - * - * @param string $name The name of the Organization. - * @param null|array $domains @deprecated 4.5.0 The domains of the Organization. Use domain_data instead. - * @param null|array $domain_data The domains of the Organization. - * @param null|boolean $allowProfilesOutsideOrganization @deprecated 4.5.0 If you need to allow sign-ins from - * any email domain, contact support@workos.com. - * @param null|string $idempotencyKey is a unique string that identifies a distinct organization - * @param null|string $externalId The organization's external id - * @param null|array $metadata The organization's metadata - * - * @throws Exception\WorkOSException - * - * @return Resource\Organization - */ - public function createOrganization( - $name, - ?array $domains = null, - ?bool $allowProfilesOutsideOrganization = null, - ?string $idempotencyKey = null, - ?array $domain_data = null, - ?string $externalId = null, - ?array $metadata = null - ) { - $idempotencyKey ? $headers = array("Idempotency-Key: $idempotencyKey") : $headers = null; - $organizationsPath = "organizations"; - - $params = ["name" => $name]; - - if (isset($domains)) { - $params["domains"] = $domains; - } - if (isset($domain_data)) { - $params["domain_data"] = $domain_data; - } - if (isset($allowProfilesOutsideOrganization)) { - $params["allow_profiles_outside_organization"] = $allowProfilesOutsideOrganization; - } - if (isset($externalId)) { - $params["external_id"] = $externalId; - } - if (isset($metadata)) { - $params["metadata"] = $metadata; - } - - $response = Client::request(Client::METHOD_POST, $organizationsPath, $headers, $params, true); - - return Resource\Organization::constructFromResponse($response); - } - - /** - * Update Organization. - * - * @param string $organization An Organization identifier. - * @param null|array $domains @deprecated 4.5.0 The domains of the Organization. Use domain_data instead. - * @param null|array $domain_data The domains of the Organization. - * @param null|string $name The name of the Organization. - * @param null|boolean $allowProfilesOutsideOrganization @deprecated 4.5.0 If you need to allow sign-ins from - * any email domain, contact support@workos.com. - * @param null|string $stripeCustomerId The Stripe Customer ID of the Organization. - * @param null|string $externalId The organization's external id - * @param null|array $metadata The organization's metadata - * - * @throws Exception\WorkOSException - */ - public function updateOrganization( - $organization, - ?array $domains = null, - ?string $name = null, - ?bool $allowProfilesOutsideOrganization = null, - ?array $domain_data = null, - ?string $stripeCustomerId = null, - ?string $externalId = null, - ?array $metadata = null - ) { - $organizationsPath = "organizations/{$organization}"; - - $params = ["name" => $name]; - - if (isset($domains)) { - $params["domains"] = $domains; - } - if (isset($domain_data)) { - $params["domain_data"] = $domain_data; - } - if (isset($allowProfilesOutsideOrganization)) { - $params["allow_profiles_outside_organization"] = $allowProfilesOutsideOrganization; - } - if (isset($stripeCustomerId)) { - $params["stripe_customer_id"] = $stripeCustomerId; - } - if (isset($externalId)) { - $params["external_id"] = $externalId; - } - if (isset($metadata)) { - $params["metadata"] = $metadata; - } - - $response = Client::request(Client::METHOD_PUT, $organizationsPath, null, $params, true); - - return Resource\Organization::constructFromResponse($response); - } - - /** - * Get an Organization - * - * @param string $organization WorkOS organization ID - * - * @throws Exception\WorkOSException - * - * @return Resource\Organization - */ - public function getOrganization($organization) - { - $organizationsPath = "organizations/{$organization}"; - - $response = Client::request(Client::METHOD_GET, $organizationsPath, null, null, true); - - return Resource\Organization::constructFromResponse($response); - } - - /** - * Get an Organization by its external id - * - * @param string $externalId external id - * - * @throws Exception\WorkOSException - * - * @return Resource\Organization - */ - public function getOrganizationByExternalId($externalId) - { - $organizationsPath = "organizations/external_id/{$externalId}"; - - $response = Client::request(Client::METHOD_GET, $organizationsPath, null, null, true); - - return Resource\Organization::constructFromResponse($response); - } - - /** - * Delete an Organization. - * - * @param string $organization WorkOS organization ID - * - * @throws Exception\WorkOSException - * - * @return Resource\Response - */ - public function deleteOrganization($organization) - { - $organizationsPath = "organizations/{$organization}"; - - $response = Client::request( - Client::METHOD_DELETE, - $organizationsPath, - null, - null, - true - ); - - return $response; - } - - /** - * List roles for an organization. - * - * @param string $organizationId WorkOS organization ID to fetch roles for - * - * @throws Exception\WorkOSException - * - * @return array{0: Resource\Role[]} An array containing the list of Role instances - */ - public function listOrganizationRoles($organizationId) - { - $organizationRolesPath = "organizations/{$organizationId}/roles"; - - $response = Client::request( - Client::METHOD_GET, - $organizationRolesPath, - null, - null, - true - ); - - $roles = []; - foreach ($response["data"] as $responseData) { - \array_push($roles, Resource\Role::constructFromResponse($responseData)); - } - - return [$roles]; - } - - /** - * List feature flags for an organization. - * - * @param string $organizationId WorkOS organization ID to fetch feature flags for - * @param int $limit Maximum number of records to return - * @param null|string $before FeatureFlag ID to look before - * @param null|string $after FeatureFlag ID to look after - * @param Resource\Order $order The Order in which to paginate records - * - * @throws Exception\WorkOSException - * - * @return Resource\PaginatedResource A paginated resource containing before/after cursors and feature_flags array. - * Supports: [$before, $after, $flags] = $result, ["feature_flags" => $flags] = $result, $result->feature_flags - */ - public function listOrganizationFeatureFlags( - $organizationId, - $limit = self::DEFAULT_PAGE_SIZE, - $before = null, - $after = null, - $order = null - ) { - $featureFlagsPath = "organizations/{$organizationId}/feature-flags"; - $params = [ - "limit" => $limit, - "before" => $before, - "after" => $after, - "order" => $order - ]; - - $response = Client::request( - Client::METHOD_GET, - $featureFlagsPath, - null, - $params, - true - ); - - return Resource\PaginatedResource::constructFromResponse($response, Resource\FeatureFlag::class, 'feature_flags'); - } -} diff --git a/lib/PKCEHelper.php b/lib/PKCEHelper.php new file mode 100644 index 00000000..8ccfab10 --- /dev/null +++ b/lib/PKCEHelper.php @@ -0,0 +1,275 @@ + 128) { + throw new \InvalidArgumentException( + "Code verifier length must be between 43 and 128, got {$length}" + ); + } + + $numBytes = intdiv($length * 3 + 3, 4); + $raw = random_bytes($numBytes); + return substr(self::base64UrlEncode($raw), 0, $length); + } + + /** + * Compute the S256 code challenge for a given verifier. + * + * @param string $verifier The code verifier string. + * @return string The base64url-encoded SHA-256 hash of the verifier. + */ + public static function generateCodeChallenge(string $verifier): string + { + $digest = hash('sha256', $verifier, true); + return self::base64UrlEncode($digest); + } + + /** + * Generate a complete PKCE pair (verifier + challenge). + * + * @return array{code_verifier: string, code_challenge: string, code_challenge_method: string} + */ + public static function generate(): array + { + $verifier = self::generateCodeVerifier(); + $challenge = self::generateCodeChallenge($verifier); + + return [ + 'code_verifier' => $verifier, + 'code_challenge' => $challenge, + 'code_challenge_method' => 'S256', + ]; + } + + // -- H10: AuthKit PKCE authorization URL -- + + /** + * Generate an AuthKit authorization URL with auto-generated PKCE parameters and state. + * + * @param string $redirectUri The redirect URI. + * @param string $clientId The WorkOS client ID. + * @param string|null $state Optional state parameter. Auto-generated if null. + * @param string|null $provider Optional auth provider. + * @param string|null $connectionId Optional connection ID. + * @param string|null $organizationId Optional organization ID. + * @param string|null $domainHint Optional domain hint. + * @param string|null $loginHint Optional login hint. + * @param string|null $screenHint Optional screen hint. + * @return array{url: mixed, code_verifier: string, state: string} + */ + public function getAuthKitAuthorizationUrl( + string $redirectUri, + string $clientId, + ?string $state = null, + ?string $provider = null, + ?string $connectionId = null, + ?string $organizationId = null, + ?string $domainHint = null, + ?string $loginHint = null, + ?string $screenHint = null, + ): array { + $pkce = self::generate(); + $state ??= bin2hex(random_bytes(16)); + + $query = array_filter([ + 'response_type' => 'code', + 'redirect_uri' => $redirectUri, + 'client_id' => $clientId, + 'code_challenge_method' => $pkce['code_challenge_method'], + 'code_challenge' => $pkce['code_challenge'], + 'state' => $state, + 'provider' => $provider, + 'connection_id' => $connectionId, + 'organization_id' => $organizationId, + 'domain_hint' => $domainHint, + 'login_hint' => $loginHint, + 'screen_hint' => $screenHint, + ], fn ($v) => $v !== null); + + $url = $this->client->request( + method: 'GET', + path: 'user_management/authorize', + query: $query, + ); + + return [ + 'url' => $url, + 'code_verifier' => $pkce['code_verifier'], + 'state' => $state, + ]; + } + + // -- H11: AuthKit PKCE code exchange -- + + /** + * Exchange an authorization code with a PKCE code verifier. + * + * @param string $code The authorization code. + * @param string $codeVerifier The PKCE code verifier. + * @param string $clientId The WorkOS client ID. + * @return array The authentication response. + */ + public function authKitCodeExchange( + string $code, + string $codeVerifier, + string $clientId, + ): array { + return $this->client->request( + method: 'POST', + path: 'user_management/authenticate', + body: [ + 'grant_type' => 'authorization_code', + 'client_id' => $clientId, + 'code' => $code, + 'code_verifier' => $codeVerifier, + ], + ); + } + + // -- H15: SSO PKCE authorization URL -- + + /** + * Generate an SSO authorization URL with auto-generated PKCE parameters and state. + * + * @param string $redirectUri The redirect URI. + * @param string $clientId The WorkOS client ID. + * @param string|null $state Optional state parameter. Auto-generated if null. + * @param string|null $domain Optional SSO domain. + * @param string|null $provider Optional SSO provider. + * @param string|null $connection Optional connection ID. + * @param string|null $organization Optional organization ID. + * @param string|null $domainHint Optional domain hint. + * @param string|null $loginHint Optional login hint. + * @return array{url: mixed, code_verifier: string, state: string} + */ + public function getSsoAuthorizationUrl( + string $redirectUri, + string $clientId, + ?string $state = null, + ?string $domain = null, + ?string $provider = null, + ?string $connection = null, + ?string $organization = null, + ?string $domainHint = null, + ?string $loginHint = null, + ): array { + $pkce = self::generate(); + $state ??= bin2hex(random_bytes(16)); + + $query = array_filter([ + 'client_id' => $clientId, + 'redirect_uri' => $redirectUri, + 'response_type' => 'code', + 'code_challenge_method' => $pkce['code_challenge_method'], + 'code_challenge' => $pkce['code_challenge'], + 'state' => $state, + 'domain' => $domain, + 'provider' => $provider, + 'connection' => $connection, + 'organization' => $organization, + 'domain_hint' => $domainHint, + 'login_hint' => $loginHint, + ], fn ($v) => $v !== null); + + $url = $this->client->request( + method: 'GET', + path: 'sso/authorize', + query: $query, + ); + + return [ + 'url' => $url, + 'code_verifier' => $pkce['code_verifier'], + 'state' => $state, + ]; + } + + // -- H16: SSO PKCE code exchange -- + + /** + * Exchange an SSO authorization code with a PKCE code verifier. + * + * @param string $code The authorization code. + * @param string $codeVerifier The PKCE code verifier. + * @param string $clientId The WorkOS client ID. + * @return array The SSO token response. + */ + public function ssoCodeExchange( + string $code, + string $codeVerifier, + string $clientId, + ): array { + return $this->client->request( + method: 'POST', + path: 'sso/token', + body: [ + 'client_id' => $clientId, + 'code' => $code, + 'code_verifier' => $codeVerifier, + 'grant_type' => 'authorization_code', + ], + ); + } + + // -- H19: Public client factory -- + + /** + * Create a WorkOS client configured for PKCE-only / public-client usage. + * + * Public clients do not use an API key (client_secret). This factory creates + * a WorkOS instance suitable for browser-side or mobile flows where the + * client secret cannot be safely stored. + * + * @param string $clientId The WorkOS client ID. + * @param string $baseUrl The WorkOS API base URL. Defaults to production. + * @return WorkOS A WorkOS client configured for public-client usage. + */ + public static function createPublicClient( + string $clientId, + string $baseUrl = 'https://api.workos.com', + ): WorkOS { + return new WorkOS( + apiKey: '', + clientId: $clientId, + baseUrl: $baseUrl, + ); + } + + // -- Internal helpers -- + + /** + * Base64url-encode without padding, per RFC 7636. + */ + private static function base64UrlEncode(string $data): string + { + return rtrim(strtr(base64_encode($data), '+/', '-_'), '='); + } +} diff --git a/lib/PaginatedResponse.php b/lib/PaginatedResponse.php new file mode 100644 index 00000000..d178f5e9 --- /dev/null +++ b/lib/PaginatedResponse.php @@ -0,0 +1,51 @@ + $modelClass::fromArray($item), $data); + } + return new self($data, $response['list_metadata'] ?? [], $fetchPage); + } + + public function hasMore(): bool + { + return ($this->listMetadata['after'] ?? null) !== null; + } + + public function autoPagingIterator(): \Generator + { + return $this->getIterator(); + } + + public function getIterator(): \Generator + { + $page = $this; + while (true) { + yield from $page->data; + if ($page->data === []) { + break; + } + if (!$page->hasMore() || $page->fetchPage === null) { + break; + } + $page = ($page->fetchPage)(['after' => $page->listMetadata['after']]); + } + } +} diff --git a/lib/Passwordless.php b/lib/Passwordless.php index 0ced82b2..48dcee14 100644 --- a/lib/Passwordless.php +++ b/lib/Passwordless.php @@ -1,72 +1,62 @@ $email, - "type" => $type - ]; - - if ($redirectUri) { - $params["redirect_uri"] = $redirectUri; - } - - if ($state) { - $params["state"] = $state; - } - - if ($connection) { - $params["connection"] = $connection; - } - - if ($expiresIn) { - $params["expires_in"] = $expiresIn; - } - - $response = Client::request(Client::METHOD_POST, $createSessionPath, null, $params, true); - - return Resource\PasswordlessSession::constructFromResponse($response); + public function createSession( + string $email, + string $type = 'MagicLink', + ?string $redirectUri = null, + ?string $state = null, + ?int $expiresIn = null, + ): array { + $body = array_filter([ + 'email' => $email, + 'type' => $type, + 'redirect_uri' => $redirectUri, + 'state' => $state, + 'expires_in' => $expiresIn, + ], fn ($v) => $v !== null); + + return $this->client->request( + method: 'POST', + path: 'passwordless/sessions', + body: $body, + ); } /** - * Send a passwordless link via email from WorkOS. - * - * @param Resource\PasswordlessSession $session Passwordless session generated through Passwordless->createSession + * Send a Passwordless Session via email. * - * @throws Exception\WorkOSException - * - * @return true + * @param string $sessionId The unique identifier of the Passwordless Session. */ - public function sendSession($session) + public function sendSession(string $sessionId): void { - $sendSessionPath = "passwordless/sessions/$session->id/send"; - Client::request(Client::METHOD_POST, $sendSessionPath, null, null, true); - - return true; + $this->client->request( + method: 'POST', + path: "passwordless/sessions/{$sessionId}/send", + body: [], + ); } } diff --git a/lib/Portal.php b/lib/Portal.php deleted file mode 100644 index 4765eb0f..00000000 --- a/lib/Portal.php +++ /dev/null @@ -1,55 +0,0 @@ - $organization, - "intent" => $intent, - "return_url" => $returnUrl, - "success_url" => $successUrl - ]; - - $response = Client::request(Client::METHOD_POST, $generateLinkPath, null, $params, true); - - return Resource\PortalLink::constructFromResponse($response); - } -} diff --git a/lib/RBAC.php b/lib/RBAC.php deleted file mode 100644 index ad23e222..00000000 --- a/lib/RBAC.php +++ /dev/null @@ -1,496 +0,0 @@ - $slug, - "name" => $name, - ]; - - if (isset($description)) { - $params["description"] = $description; - } - if (isset($resourceTypeSlug)) { - $params["resource_type_slug"] = $resourceTypeSlug; - } - - $response = Client::request(Client::METHOD_POST, $path, null, $params, true); - - return Resource\Permission::constructFromResponse($response); - } - - /** - * List Permissions. - * - * @param int $limit Maximum number of records to return - * @param null|string $before Permission ID to look before - * @param null|string $after Permission ID to look after - * @param null|string $order The order in which to paginate records - * - * @throws Exception\WorkOSException - * - * @return Resource\PaginatedResource - */ - public function listPermissions( - int $limit = self::DEFAULT_PAGE_SIZE, - ?string $before = null, - ?string $after = null, - ?string $order = null - ) { - $path = "authorization/permissions"; - - $params = [ - "limit" => $limit, - "before" => $before, - "after" => $after, - "order" => $order, - ]; - - $response = Client::request(Client::METHOD_GET, $path, null, $params, true); - - return Resource\PaginatedResource::constructFromResponse($response, Resource\Permission::class, 'permissions'); - } - - /** - * Get a Permission. - * - * @param string $slug The slug of the Permission - * - * @throws Exception\WorkOSException - * - * @return Resource\Permission - */ - public function getPermission(string $slug) - { - $path = "authorization/permissions/{$slug}"; - - $response = Client::request(Client::METHOD_GET, $path, null, null, true); - - return Resource\Permission::constructFromResponse($response); - } - - /** - * Update a Permission. - * - * @param string $slug The slug of the Permission to update - * @param null|string $name The updated name of the Permission - * @param null|string $description The updated description of the Permission - * - * @throws Exception\WorkOSException - * - * @return Resource\Permission - */ - public function updatePermission( - string $slug, - ?string $name = null, - ?string $description = null - ) { - $path = "authorization/permissions/{$slug}"; - - $params = []; - - if (isset($name)) { - $params["name"] = $name; - } - if (isset($description)) { - $params["description"] = $description; - } - - $response = Client::request(Client::METHOD_PATCH, $path, null, $params, true); - - return Resource\Permission::constructFromResponse($response); - } - - /** - * Delete a Permission. - * - * @param string $slug The slug of the Permission to delete - * - * @throws Exception\WorkOSException - * - * @return array - */ - public function deletePermission(string $slug) - { - $path = "authorization/permissions/{$slug}"; - - $response = Client::request(Client::METHOD_DELETE, $path, null, null, true); - - return $response; - } - - /** - * Create an Environment Role. - * - * @param string $slug The slug of the Role - * @param string $name The name of the Role - * @param null|string $description The description of the Role - * @param null|string $resourceTypeSlug The resource type slug of the Role - * - * @throws Exception\WorkOSException - * - * @return Resource\Role - */ - public function createEnvironmentRole( - string $slug, - string $name, - ?string $description = null, - ?string $resourceTypeSlug = null - ) { - $path = "authorization/roles"; - - $params = [ - "slug" => $slug, - "name" => $name, - ]; - - if (isset($description)) { - $params["description"] = $description; - } - if (isset($resourceTypeSlug)) { - $params["resource_type_slug"] = $resourceTypeSlug; - } - - $response = Client::request(Client::METHOD_POST, $path, null, $params, true); - - return Resource\Role::constructFromResponse($response); - } - - /** - * List Environment Roles. - * - * @throws Exception\WorkOSException - * - * @return Resource\Role[] - */ - public function listEnvironmentRoles() - { - $path = "authorization/roles"; - - $response = Client::request(Client::METHOD_GET, $path, null, null, true); - - $roles = []; - foreach ($response["data"] as $responseData) { - \array_push($roles, Resource\Role::constructFromResponse($responseData)); - } - - return $roles; - } - - /** - * Get an Environment Role. - * - * @param string $slug The slug of the Role - * - * @throws Exception\WorkOSException - * - * @return Resource\Role - */ - public function getEnvironmentRole(string $slug) - { - $path = "authorization/roles/{$slug}"; - - $response = Client::request(Client::METHOD_GET, $path, null, null, true); - - return Resource\Role::constructFromResponse($response); - } - - /** - * Update an Environment Role. - * - * @param string $slug The slug of the Role to update - * @param null|string $name The updated name of the Role - * @param null|string $description The updated description of the Role - * - * @throws Exception\WorkOSException - * - * @return Resource\Role - */ - public function updateEnvironmentRole( - string $slug, - ?string $name = null, - ?string $description = null - ) { - $path = "authorization/roles/{$slug}"; - - $params = []; - - if (isset($name)) { - $params["name"] = $name; - } - if (isset($description)) { - $params["description"] = $description; - } - - $response = Client::request(Client::METHOD_PATCH, $path, null, $params, true); - - return Resource\Role::constructFromResponse($response); - } - - /** - * Set permissions for an Environment Role. - * - * @param string $slug The slug of the Role - * @param array $permissions The permission slugs to set on the Role - * - * @throws Exception\WorkOSException - * - * @return Resource\Role - */ - public function setEnvironmentRolePermissions(string $slug, array $permissions) - { - $path = "authorization/roles/{$slug}/permissions"; - - $params = [ - "permissions" => $permissions, - ]; - - $response = Client::request(Client::METHOD_PUT, $path, null, $params, true); - - return Resource\Role::constructFromResponse($response); - } - - /** - * Add a permission to an Environment Role. - * - * @param string $roleSlug The slug of the Role - * @param string $permissionSlug The slug of the Permission to add - * - * @throws Exception\WorkOSException - * - * @return Resource\Role - */ - public function addEnvironmentRolePermission(string $roleSlug, string $permissionSlug) - { - $path = "authorization/roles/{$roleSlug}/permissions"; - - $params = [ - "slug" => $permissionSlug, - ]; - - $response = Client::request(Client::METHOD_POST, $path, null, $params, true); - - return Resource\Role::constructFromResponse($response); - } - - /** - * Create an Organization Role. - * - * @param string $organizationId WorkOS Organization ID - * @param string $slug The slug of the Role - * @param string $name The name of the Role - * @param null|string $description The description of the Role - * - * @throws Exception\WorkOSException - * - * @return Resource\Role - */ - public function createOrganizationRole( - string $organizationId, - string $slug, - string $name, - ?string $description = null - ) { - $path = "authorization/organizations/{$organizationId}/roles"; - - $params = [ - "slug" => $slug, - "name" => $name, - ]; - - if (isset($description)) { - $params["description"] = $description; - } - - $response = Client::request(Client::METHOD_POST, $path, null, $params, true); - - return Resource\Role::constructFromResponse($response); - } - - /** - * List Organization Roles. - * - * @param string $organizationId WorkOS Organization ID - * - * @throws Exception\WorkOSException - * - * @return Resource\Role[] - */ - public function listOrganizationRoles(string $organizationId) - { - $path = "authorization/organizations/{$organizationId}/roles"; - - $response = Client::request(Client::METHOD_GET, $path, null, null, true); - - $roles = []; - foreach ($response["data"] as $responseData) { - \array_push($roles, Resource\Role::constructFromResponse($responseData)); - } - - return $roles; - } - - /** - * Get an Organization Role. - * - * @param string $organizationId WorkOS Organization ID - * @param string $slug The slug of the Role - * - * @throws Exception\WorkOSException - * - * @return Resource\Role - */ - public function getOrganizationRole(string $organizationId, string $slug) - { - $path = "authorization/organizations/{$organizationId}/roles/{$slug}"; - - $response = Client::request(Client::METHOD_GET, $path, null, null, true); - - return Resource\Role::constructFromResponse($response); - } - - /** - * Update an Organization Role. - * - * @param string $organizationId WorkOS Organization ID - * @param string $slug The slug of the Role to update - * @param null|string $name The updated name of the Role - * @param null|string $description The updated description of the Role - * - * @throws Exception\WorkOSException - * - * @return Resource\Role - */ - public function updateOrganizationRole( - string $organizationId, - string $slug, - ?string $name = null, - ?string $description = null - ) { - $path = "authorization/organizations/{$organizationId}/roles/{$slug}"; - - $params = []; - - if (isset($name)) { - $params["name"] = $name; - } - if (isset($description)) { - $params["description"] = $description; - } - - $response = Client::request(Client::METHOD_PATCH, $path, null, $params, true); - - return Resource\Role::constructFromResponse($response); - } - - /** - * Delete an Organization Role. - * - * @param string $organizationId WorkOS Organization ID - * @param string $slug The slug of the Role to delete - * - * @throws Exception\WorkOSException - * - * @return array - */ - public function deleteOrganizationRole(string $organizationId, string $slug) - { - $path = "authorization/organizations/{$organizationId}/roles/{$slug}"; - - $response = Client::request(Client::METHOD_DELETE, $path, null, null, true); - - return $response; - } - - /** - * Set permissions for an Organization Role. - * - * @param string $organizationId WorkOS Organization ID - * @param string $slug The slug of the Role - * @param array $permissions The permission slugs to set on the Role - * - * @throws Exception\WorkOSException - * - * @return Resource\Role - */ - public function setOrganizationRolePermissions(string $organizationId, string $slug, array $permissions) - { - $path = "authorization/organizations/{$organizationId}/roles/{$slug}/permissions"; - - $params = [ - "permissions" => $permissions, - ]; - - $response = Client::request(Client::METHOD_PUT, $path, null, $params, true); - - return Resource\Role::constructFromResponse($response); - } - - /** - * Add a permission to an Organization Role. - * - * @param string $organizationId WorkOS Organization ID - * @param string $roleSlug The slug of the Role - * @param string $permissionSlug The slug of the Permission to add - * - * @throws Exception\WorkOSException - * - * @return Resource\Role - */ - public function addOrganizationRolePermission(string $organizationId, string $roleSlug, string $permissionSlug) - { - $path = "authorization/organizations/{$organizationId}/roles/{$roleSlug}/permissions"; - - $params = [ - "slug" => $permissionSlug, - ]; - - $response = Client::request(Client::METHOD_POST, $path, null, $params, true); - - return Resource\Role::constructFromResponse($response); - } - - /** - * Remove a permission from an Organization Role. - * - * @param string $organizationId WorkOS Organization ID - * @param string $roleSlug The slug of the Role - * @param string $permissionSlug The slug of the Permission to remove - * - * @throws Exception\WorkOSException - * - * @return array - */ - public function removeOrganizationRolePermission(string $organizationId, string $roleSlug, string $permissionSlug) - { - $path = "authorization/organizations/{$organizationId}/roles/{$roleSlug}/permissions/{$permissionSlug}"; - - $response = Client::request(Client::METHOD_DELETE, $path, null, null, true); - - return $response; - } -} diff --git a/lib/RequestClient/CurlRequestClient.php b/lib/RequestClient/CurlRequestClient.php deleted file mode 100644 index 581249df..00000000 --- a/lib/RequestClient/CurlRequestClient.php +++ /dev/null @@ -1,128 +0,0 @@ - 1]; - - switch ($method) { - case Client::METHOD_GET: - if (!empty($params)) { - $url .= "?" . http_build_query($params); - } - - break; - - case Client::METHOD_POST: - \array_push($headers, "Content-Type: application/json"); - - $opts[\CURLOPT_POST] = 1; - - if (!empty($params)) { - $opts[\CURLOPT_POSTFIELDS] = \json_encode($params); - } - - break; - - case Client::METHOD_DELETE: - - $opts[\CURLOPT_CUSTOMREQUEST] = 'DELETE'; - - if (!empty($params)) { - $encoded = Util\Util::encodeParameters($params); - $absUrl = "{$absUrl}?{$encoded}"; - } - - break; - - case Client::METHOD_PUT: - - \array_push($headers, "Content-Type: application/json"); - - $opts[\CURLOPT_CUSTOMREQUEST] = 'PUT'; - - $opts[\CURLOPT_POST] = 1; - - if (!empty($params)) { - $opts[\CURLOPT_POSTFIELDS] = \json_encode($params); - } - - break; - - case Client::METHOD_PATCH: - \array_push($headers, "Content-Type: application/json"); - $opts[\CURLOPT_CUSTOMREQUEST] = 'PATCH'; - $opts[\CURLOPT_POST] = 1; - if (!empty($params)) { - $opts[\CURLOPT_POSTFIELDS] = \json_encode($params); - } - break; - } - - $opts[\CURLOPT_HTTPHEADER] = $headers; - $opts[\CURLOPT_URL] = $url; - - return self::execute($opts); - } - - private function execute($opts) - { - $curl = \curl_init(); - - $headers = array(); - $headerCallback = function ($curl, $header_line) use (&$headers) { - if (false === \strpos($header_line, ":")) { - return \strlen($header_line); - } - - list($key, $value) = \explode(":", \trim($header_line), 2); - $headers[\trim($key)] = \trim($value); - - return \strlen($header_line); - }; - $opts[\CURLOPT_HEADERFUNCTION] = $headerCallback; - \curl_setopt_array($curl, $opts); - - $result = \curl_exec($curl); - - // I think this is for some sort of internal error - // Any kind of response that returns a status code won"t hit this block - if ($result === false) { - $errno = \curl_errno($curl); - $msg = \curl_error($curl); - \curl_close($curl); - - throw new GenericException($msg, ["curlErrno" => $errno]); - } else { - // Unsure how versions of cURL and PHP correlate so using the legacy - // reference for getting the last response code - $statusCode = \curl_getinfo($curl, \CURLINFO_RESPONSE_CODE); - \curl_close($curl); - - return [$result, $headers, $statusCode]; - } - } -} diff --git a/lib/RequestClient/RequestClientInterface.php b/lib/RequestClient/RequestClientInterface.php deleted file mode 100644 index a140240c..00000000 --- a/lib/RequestClient/RequestClientInterface.php +++ /dev/null @@ -1,23 +0,0 @@ - $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/ActionAuthenticationDeniedContext.php b/lib/Resource/ActionAuthenticationDeniedContext.php new file mode 100644 index 00000000..41a6b9f2 --- /dev/null +++ b/lib/Resource/ActionAuthenticationDeniedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?ActionAuthenticationDeniedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? ActionAuthenticationDeniedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/ActionAuthenticationDeniedContextActor.php b/lib/Resource/ActionAuthenticationDeniedContextActor.php new file mode 100644 index 00000000..a9537a3f --- /dev/null +++ b/lib/Resource/ActionAuthenticationDeniedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/ActionAuthenticationDeniedContextGoogleAnalyticsSession.php b/lib/Resource/ActionAuthenticationDeniedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..c60029fd --- /dev/null +++ b/lib/Resource/ActionAuthenticationDeniedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/ActionAuthenticationDeniedData.php b/lib/Resource/ActionAuthenticationDeniedData.php new file mode 100644 index 00000000..1bca6fc7 --- /dev/null +++ b/lib/Resource/ActionAuthenticationDeniedData.php @@ -0,0 +1,65 @@ + $this->actionEndpointId, + 'action_execution_id' => $this->actionExecutionId, + 'type' => $this->type, + 'verdict' => $this->verdict, + 'user_id' => $this->userId, + 'organization_id' => $this->organizationId, + 'email' => $this->email, + 'ip_address' => $this->ipAddress, + 'user_agent' => $this->userAgent, + ]; + } +} diff --git a/lib/Resource/ActionUserRegistrationDenied.php b/lib/Resource/ActionUserRegistrationDenied.php new file mode 100644 index 00000000..072dd9ed --- /dev/null +++ b/lib/Resource/ActionUserRegistrationDenied.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/ActionUserRegistrationDeniedContext.php b/lib/Resource/ActionUserRegistrationDeniedContext.php new file mode 100644 index 00000000..6b252f2b --- /dev/null +++ b/lib/Resource/ActionUserRegistrationDeniedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?ActionUserRegistrationDeniedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? ActionUserRegistrationDeniedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/ActionUserRegistrationDeniedContextActor.php b/lib/Resource/ActionUserRegistrationDeniedContextActor.php new file mode 100644 index 00000000..b91e63c1 --- /dev/null +++ b/lib/Resource/ActionUserRegistrationDeniedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/ActionUserRegistrationDeniedContextGoogleAnalyticsSession.php b/lib/Resource/ActionUserRegistrationDeniedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..0105e652 --- /dev/null +++ b/lib/Resource/ActionUserRegistrationDeniedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/ActionUserRegistrationDeniedData.php b/lib/Resource/ActionUserRegistrationDeniedData.php new file mode 100644 index 00000000..4afbe0d2 --- /dev/null +++ b/lib/Resource/ActionUserRegistrationDeniedData.php @@ -0,0 +1,61 @@ + $this->actionEndpointId, + 'action_execution_id' => $this->actionExecutionId, + 'type' => $this->type, + 'verdict' => $this->verdict, + 'organization_id' => $this->organizationId, + 'email' => $this->email, + 'ip_address' => $this->ipAddress, + 'user_agent' => $this->userAgent, + ]; + } +} diff --git a/lib/Resource/AddRolePermission.php b/lib/Resource/AddRolePermission.php new file mode 100644 index 00000000..15368fba --- /dev/null +++ b/lib/Resource/AddRolePermission.php @@ -0,0 +1,32 @@ + $this->slug, + ]; + } +} diff --git a/lib/Resource/ApiKey.php b/lib/Resource/ApiKey.php new file mode 100644 index 00000000..6dff0317 --- /dev/null +++ b/lib/Resource/ApiKey.php @@ -0,0 +1,68 @@ + + */ + public array $permissions, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + owner: ApiKeyOwner::fromArray($data['owner']), + name: $data['name'], + obfuscatedValue: $data['obfuscated_value'], + lastUsedAt: isset($data['last_used_at']) ? new \DateTimeImmutable($data['last_used_at']) : null, + permissions: $data['permissions'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'owner' => $this->owner->toArray(), + 'name' => $this->name, + 'obfuscated_value' => $this->obfuscatedValue, + 'last_used_at' => $this->lastUsedAt?->format(\DateTimeInterface::RFC3339_EXTENDED), + 'permissions' => $this->permissions, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/ApiKeyCreated.php b/lib/Resource/ApiKeyCreated.php new file mode 100644 index 00000000..52979aa7 --- /dev/null +++ b/lib/Resource/ApiKeyCreated.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/ApiKeyCreatedContext.php b/lib/Resource/ApiKeyCreatedContext.php new file mode 100644 index 00000000..b1fe50bd --- /dev/null +++ b/lib/Resource/ApiKeyCreatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?ApiKeyCreatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? ApiKeyCreatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/ApiKeyCreatedContextActor.php b/lib/Resource/ApiKeyCreatedContextActor.php new file mode 100644 index 00000000..fe05f74e --- /dev/null +++ b/lib/Resource/ApiKeyCreatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/ApiKeyCreatedContextGoogleAnalyticsSession.php b/lib/Resource/ApiKeyCreatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..1e2eeb9a --- /dev/null +++ b/lib/Resource/ApiKeyCreatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/ApiKeyCreatedData.php b/lib/Resource/ApiKeyCreatedData.php new file mode 100644 index 00000000..97e21082 --- /dev/null +++ b/lib/Resource/ApiKeyCreatedData.php @@ -0,0 +1,68 @@ + + */ + public array $permissions, + /** The timestamp when the API key was created. */ + public string $createdAt, + /** The timestamp when the API key was last updated. */ + public string $updatedAt, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + owner: ApiKeyCreatedDataOwner::fromArray($data['owner']), + name: $data['name'], + obfuscatedValue: $data['obfuscated_value'], + lastUsedAt: $data['last_used_at'] ?? null, + permissions: $data['permissions'], + createdAt: $data['created_at'], + updatedAt: $data['updated_at'], + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'owner' => $this->owner->toArray(), + 'name' => $this->name, + 'obfuscated_value' => $this->obfuscatedValue, + 'last_used_at' => $this->lastUsedAt, + 'permissions' => $this->permissions, + 'created_at' => $this->createdAt, + 'updated_at' => $this->updatedAt, + ]; + } +} diff --git a/lib/Resource/ApiKeyCreatedDataOwner.php b/lib/Resource/ApiKeyCreatedDataOwner.php new file mode 100644 index 00000000..f24f31e9 --- /dev/null +++ b/lib/Resource/ApiKeyCreatedDataOwner.php @@ -0,0 +1,37 @@ + $this->type, + 'id' => $this->id, + ]; + } +} diff --git a/lib/Resource/ApiKeyOwner.php b/lib/Resource/ApiKeyOwner.php new file mode 100644 index 00000000..934b8ced --- /dev/null +++ b/lib/Resource/ApiKeyOwner.php @@ -0,0 +1,37 @@ + $this->type, + 'id' => $this->id, + ]; + } +} diff --git a/lib/Resource/ApiKeyRevoked.php b/lib/Resource/ApiKeyRevoked.php new file mode 100644 index 00000000..799015e0 --- /dev/null +++ b/lib/Resource/ApiKeyRevoked.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/ApiKeyRevokedContext.php b/lib/Resource/ApiKeyRevokedContext.php new file mode 100644 index 00000000..133bbc08 --- /dev/null +++ b/lib/Resource/ApiKeyRevokedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?ApiKeyRevokedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? ApiKeyRevokedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/ApiKeyRevokedContextActor.php b/lib/Resource/ApiKeyRevokedContextActor.php new file mode 100644 index 00000000..8fd7d625 --- /dev/null +++ b/lib/Resource/ApiKeyRevokedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/ApiKeyRevokedContextGoogleAnalyticsSession.php b/lib/Resource/ApiKeyRevokedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..b4472f27 --- /dev/null +++ b/lib/Resource/ApiKeyRevokedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/ApiKeyRevokedData.php b/lib/Resource/ApiKeyRevokedData.php new file mode 100644 index 00000000..90dae477 --- /dev/null +++ b/lib/Resource/ApiKeyRevokedData.php @@ -0,0 +1,68 @@ + + */ + public array $permissions, + /** The timestamp when the API key was created. */ + public string $createdAt, + /** The timestamp when the API key was last updated. */ + public string $updatedAt, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + owner: ApiKeyRevokedDataOwner::fromArray($data['owner']), + name: $data['name'], + obfuscatedValue: $data['obfuscated_value'], + lastUsedAt: $data['last_used_at'] ?? null, + permissions: $data['permissions'], + createdAt: $data['created_at'], + updatedAt: $data['updated_at'], + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'owner' => $this->owner->toArray(), + 'name' => $this->name, + 'obfuscated_value' => $this->obfuscatedValue, + 'last_used_at' => $this->lastUsedAt, + 'permissions' => $this->permissions, + 'created_at' => $this->createdAt, + 'updated_at' => $this->updatedAt, + ]; + } +} diff --git a/lib/Resource/ApiKeyRevokedDataOwner.php b/lib/Resource/ApiKeyRevokedDataOwner.php new file mode 100644 index 00000000..21e5192b --- /dev/null +++ b/lib/Resource/ApiKeyRevokedDataOwner.php @@ -0,0 +1,37 @@ + $this->type, + 'id' => $this->id, + ]; + } +} diff --git a/lib/Resource/ApiKeyValidationResponse.php b/lib/Resource/ApiKeyValidationResponse.php new file mode 100644 index 00000000..61553404 --- /dev/null +++ b/lib/Resource/ApiKeyValidationResponse.php @@ -0,0 +1,31 @@ + $this->apiKey?->toArray(), + ]; + } +} diff --git a/lib/Resource/ApiKeyWithValue.php b/lib/Resource/ApiKeyWithValue.php new file mode 100644 index 00000000..f5e83a9e --- /dev/null +++ b/lib/Resource/ApiKeyWithValue.php @@ -0,0 +1,71 @@ + + */ + public array $permissions, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + /** The full API Key value. Only returned once at creation time. */ + public string $value, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + owner: ApiKeyWithValueOwner::fromArray($data['owner']), + name: $data['name'], + obfuscatedValue: $data['obfuscated_value'], + lastUsedAt: isset($data['last_used_at']) ? new \DateTimeImmutable($data['last_used_at']) : null, + permissions: $data['permissions'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + value: $data['value'], + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'owner' => $this->owner->toArray(), + 'name' => $this->name, + 'obfuscated_value' => $this->obfuscatedValue, + 'last_used_at' => $this->lastUsedAt?->format(\DateTimeInterface::RFC3339_EXTENDED), + 'permissions' => $this->permissions, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'value' => $this->value, + ]; + } +} diff --git a/lib/Resource/ApiKeyWithValueOwner.php b/lib/Resource/ApiKeyWithValueOwner.php new file mode 100644 index 00000000..890402ce --- /dev/null +++ b/lib/Resource/ApiKeyWithValueOwner.php @@ -0,0 +1,37 @@ + $this->type, + 'id' => $this->id, + ]; + } +} diff --git a/lib/Resource/ApplicationCredentialsListItem.php b/lib/Resource/ApplicationCredentialsListItem.php new file mode 100644 index 00000000..0f605ecb --- /dev/null +++ b/lib/Resource/ApplicationCredentialsListItem.php @@ -0,0 +1,52 @@ + $this->object, + 'id' => $this->id, + 'secret_hint' => $this->secretHint, + 'last_used_at' => $this->lastUsedAt, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/ApplicationsOrder.php b/lib/Resource/ApplicationsOrder.php new file mode 100644 index 00000000..99aafc27 --- /dev/null +++ b/lib/Resource/ApplicationsOrder.php @@ -0,0 +1,14 @@ + $this->roleSlug, + 'resource_id' => $this->resourceId, + 'resource_external_id' => $this->resourceExternalId, + 'resource_type_slug' => $this->resourceTypeSlug, + ]; + } +} diff --git a/lib/Resource/AuditLogActionJson.php b/lib/Resource/AuditLogActionJson.php new file mode 100644 index 00000000..c992d0c5 --- /dev/null +++ b/lib/Resource/AuditLogActionJson.php @@ -0,0 +1,48 @@ + $this->object, + 'name' => $this->name, + 'schema' => $this->schema->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/AuditLogConfiguration.php b/lib/Resource/AuditLogConfiguration.php new file mode 100644 index 00000000..01c26672 --- /dev/null +++ b/lib/Resource/AuditLogConfiguration.php @@ -0,0 +1,44 @@ + $this->organizationId, + 'retention_period_in_days' => $this->retentionPeriodInDays, + 'state' => $this->state->value, + 'log_stream' => $this->logStream?->toArray(), + ]; + } +} diff --git a/lib/Resource/AuditLogConfigurationLogStream.php b/lib/Resource/AuditLogConfigurationLogStream.php new file mode 100644 index 00000000..2a43d6ae --- /dev/null +++ b/lib/Resource/AuditLogConfigurationLogStream.php @@ -0,0 +1,49 @@ + $this->id, + 'type' => $this->type->value, + 'state' => $this->state->value, + 'last_synced_at' => $this->lastSyncedAt, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/AuditLogConfigurationLogStreamState.php b/lib/Resource/AuditLogConfigurationLogStreamState.php new file mode 100644 index 00000000..cda4e93e --- /dev/null +++ b/lib/Resource/AuditLogConfigurationLogStreamState.php @@ -0,0 +1,15 @@ + "success" - ]; -} diff --git a/lib/Resource/AuditLogEvent.php b/lib/Resource/AuditLogEvent.php new file mode 100644 index 00000000..2b5527c2 --- /dev/null +++ b/lib/Resource/AuditLogEvent.php @@ -0,0 +1,62 @@ + + */ + public array $targets, + /** Additional context about where and how the action occurred. */ + public AuditLogEventContext $context, + /** + * Additional data associated with the event or entity. + * @var array|null + */ + public ?array $metadata = null, + /** What schema version the event is associated with. */ + public ?int $version = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + action: $data['action'], + occurredAt: new \DateTimeImmutable($data['occurred_at']), + actor: AuditLogEventActor::fromArray($data['actor']), + targets: array_map(fn ($item) => AuditLogEventTarget::fromArray($item), $data['targets']), + context: AuditLogEventContext::fromArray($data['context']), + metadata: $data['metadata'] ?? null, + version: $data['version'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'action' => $this->action, + 'occurred_at' => $this->occurredAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'actor' => $this->actor->toArray(), + 'targets' => array_map(fn ($item) => $item->toArray(), $this->targets), + 'context' => $this->context->toArray(), + 'metadata' => $this->metadata, + 'version' => $this->version, + ]; + } +} diff --git a/lib/Resource/AuditLogEventActor.php b/lib/Resource/AuditLogEventActor.php new file mode 100644 index 00000000..4af232d7 --- /dev/null +++ b/lib/Resource/AuditLogEventActor.php @@ -0,0 +1,47 @@ +|null + */ + public ?array $metadata = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + id: $data['id'], + type: $data['type'], + name: $data['name'] ?? null, + metadata: $data['metadata'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'id' => $this->id, + 'type' => $this->type, + 'name' => $this->name, + 'metadata' => $this->metadata, + ]; + } +} diff --git a/lib/Resource/AuditLogEventContext.php b/lib/Resource/AuditLogEventContext.php new file mode 100644 index 00000000..0cc3f148 --- /dev/null +++ b/lib/Resource/AuditLogEventContext.php @@ -0,0 +1,36 @@ + $this->location, + 'user_agent' => $this->userAgent, + ]; + } +} diff --git a/lib/Resource/AuditLogEventCreateResponse.php b/lib/Resource/AuditLogEventCreateResponse.php new file mode 100644 index 00000000..f2daafaf --- /dev/null +++ b/lib/Resource/AuditLogEventCreateResponse.php @@ -0,0 +1,32 @@ + $this->success, + ]; + } +} diff --git a/lib/Resource/AuditLogEventIngestion.php b/lib/Resource/AuditLogEventIngestion.php new file mode 100644 index 00000000..fe6d6425 --- /dev/null +++ b/lib/Resource/AuditLogEventIngestion.php @@ -0,0 +1,36 @@ + $this->organizationId, + 'event' => $this->event->toArray(), + ]; + } +} diff --git a/lib/Resource/AuditLogEventTarget.php b/lib/Resource/AuditLogEventTarget.php new file mode 100644 index 00000000..1eab461f --- /dev/null +++ b/lib/Resource/AuditLogEventTarget.php @@ -0,0 +1,47 @@ +|null + */ + public ?array $metadata = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + id: $data['id'], + type: $data['type'], + name: $data['name'] ?? null, + metadata: $data['metadata'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'id' => $this->id, + 'type' => $this->type, + 'name' => $this->name, + 'metadata' => $this->metadata, + ]; + } +} diff --git a/lib/Resource/AuditLogExport.php b/lib/Resource/AuditLogExport.php deleted file mode 100644 index 93e8348b..00000000 --- a/lib/Resource/AuditLogExport.php +++ /dev/null @@ -1,29 +0,0 @@ - "object", - "id" => "id", - "state" => "state", - "url" => "url", - "created_at" => "createdAt", - "updated_at" => "updatedAt" - ]; -} diff --git a/lib/Resource/AuditLogExportCreation.php b/lib/Resource/AuditLogExportCreation.php new file mode 100644 index 00000000..26770390 --- /dev/null +++ b/lib/Resource/AuditLogExportCreation.php @@ -0,0 +1,76 @@ +|null + */ + public ?array $actions = null, + /** + * Deprecated. Use `actor_names` instead. + * @var array|null + * @deprecated + */ + public ?array $actors = null, + /** + * List of actor names to filter against. + * @var array|null + */ + public ?array $actorNames = null, + /** + * List of actor IDs to filter against. + * @var array|null + */ + public ?array $actorIds = null, + /** + * List of target types to filter against. + * @var array|null + */ + public ?array $targets = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + organizationId: $data['organization_id'], + rangeStart: $data['range_start'], + rangeEnd: $data['range_end'], + actions: $data['actions'] ?? null, + actors: $data['actors'] ?? null, + actorNames: $data['actor_names'] ?? null, + actorIds: $data['actor_ids'] ?? null, + targets: $data['targets'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'organization_id' => $this->organizationId, + 'range_start' => $this->rangeStart, + 'range_end' => $this->rangeEnd, + 'actions' => $this->actions, + 'actors' => $this->actors, + 'actor_names' => $this->actorNames, + 'actor_ids' => $this->actorIds, + 'targets' => $this->targets, + ]; + } +} diff --git a/lib/Resource/AuditLogExportJson.php b/lib/Resource/AuditLogExportJson.php new file mode 100644 index 00000000..43bdc2f0 --- /dev/null +++ b/lib/Resource/AuditLogExportJson.php @@ -0,0 +1,52 @@ + $this->object, + 'id' => $this->id, + 'state' => $this->state->value, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'url' => $this->url, + ]; + } +} diff --git a/lib/Resource/AuditLogExportJsonState.php b/lib/Resource/AuditLogExportJsonState.php new file mode 100644 index 00000000..2e42296c --- /dev/null +++ b/lib/Resource/AuditLogExportJsonState.php @@ -0,0 +1,14 @@ + + */ + public array $targets, + /** The metadata schema for the actor. */ + public ?AuditLogSchemaActor $actor = null, + /** + * Optional JSON schema for event metadata. + * @var array|null + */ + public ?array $metadata = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + targets: array_map(fn ($item) => AuditLogSchemaTarget::fromArray($item), $data['targets']), + actor: isset($data['actor']) ? AuditLogSchemaActor::fromArray($data['actor']) : null, + metadata: $data['metadata'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'targets' => array_map(fn ($item) => $item->toArray(), $this->targets), + 'actor' => $this->actor?->toArray(), + 'metadata' => $this->metadata, + ]; + } +} diff --git a/lib/Resource/AuditLogSchemaActor.php b/lib/Resource/AuditLogSchemaActor.php new file mode 100644 index 00000000..51176983 --- /dev/null +++ b/lib/Resource/AuditLogSchemaActor.php @@ -0,0 +1,35 @@ + + */ + public array $metadata, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + metadata: $data['metadata'], + ); + } + + public function toArray(): array + { + return [ + 'metadata' => $this->metadata, + ]; + } +} diff --git a/lib/Resource/AuditLogSchemaJson.php b/lib/Resource/AuditLogSchemaJson.php new file mode 100644 index 00000000..b67c461a --- /dev/null +++ b/lib/Resource/AuditLogSchemaJson.php @@ -0,0 +1,58 @@ + + */ + public array $targets, + /** The timestamp when the Audit Log Schema was created. */ + public \DateTimeImmutable $createdAt, + /** The metadata schema for the actor. */ + public ?AuditLogSchemaJsonActor $actor = null, + /** + * Additional data associated with the event or entity. + * @var array|null + */ + public ?array $metadata = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + version: $data['version'], + targets: array_map(fn ($item) => AuditLogSchemaJsonTarget::fromArray($item), $data['targets']), + createdAt: new \DateTimeImmutable($data['created_at']), + actor: isset($data['actor']) ? AuditLogSchemaJsonActor::fromArray($data['actor']) : null, + metadata: $data['metadata'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'version' => $this->version, + 'targets' => array_map(fn ($item) => $item->toArray(), $this->targets), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'actor' => $this->actor?->toArray(), + 'metadata' => $this->metadata, + ]; + } +} diff --git a/lib/Resource/AuditLogSchemaJsonActor.php b/lib/Resource/AuditLogSchemaJsonActor.php new file mode 100644 index 00000000..3d9dcd84 --- /dev/null +++ b/lib/Resource/AuditLogSchemaJsonActor.php @@ -0,0 +1,36 @@ + + */ + public array $metadata, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + metadata: $data['metadata'], + ); + } + + public function toArray(): array + { + return [ + 'metadata' => $this->metadata, + ]; + } +} diff --git a/lib/Resource/AuditLogSchemaJsonTarget.php b/lib/Resource/AuditLogSchemaJsonTarget.php new file mode 100644 index 00000000..8579e35f --- /dev/null +++ b/lib/Resource/AuditLogSchemaJsonTarget.php @@ -0,0 +1,39 @@ +|null + */ + public ?array $metadata = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + type: $data['type'], + metadata: $data['metadata'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'type' => $this->type, + 'metadata' => $this->metadata, + ]; + } +} diff --git a/lib/Resource/AuditLogSchemaTarget.php b/lib/Resource/AuditLogSchemaTarget.php new file mode 100644 index 00000000..b26040a0 --- /dev/null +++ b/lib/Resource/AuditLogSchemaTarget.php @@ -0,0 +1,39 @@ +|null + */ + public ?array $metadata = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + type: $data['type'], + metadata: $data['metadata'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'type' => $this->type, + 'metadata' => $this->metadata, + ]; + } +} diff --git a/lib/Resource/AuditLogsOrder.php b/lib/Resource/AuditLogsOrder.php new file mode 100644 index 00000000..3f8ce6f3 --- /dev/null +++ b/lib/Resource/AuditLogsOrder.php @@ -0,0 +1,14 @@ + $this->retentionPeriodInDays, + ]; + } +} diff --git a/lib/Resource/AuthenticateResponse.php b/lib/Resource/AuthenticateResponse.php new file mode 100644 index 00000000..dd21f11a --- /dev/null +++ b/lib/Resource/AuthenticateResponse.php @@ -0,0 +1,60 @@ + $this->user->toArray(), + 'access_token' => $this->accessToken, + 'refresh_token' => $this->refreshToken, + 'organization_id' => $this->organizationId, + 'authkit_authorization_code' => $this->authkitAuthorizationCode, + 'authentication_method' => $this->authenticationMethod?->value, + 'impersonator' => $this->impersonator?->toArray(), + 'oauth_tokens' => $this->oauthTokens?->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticateResponseAuthenticationMethod.php b/lib/Resource/AuthenticateResponseAuthenticationMethod.php new file mode 100644 index 00000000..ad41b642 --- /dev/null +++ b/lib/Resource/AuthenticateResponseAuthenticationMethod.php @@ -0,0 +1,33 @@ + $this->email, + 'reason' => $this->reason, + ]; + } +} diff --git a/lib/Resource/AuthenticateResponseOAuthToken.php b/lib/Resource/AuthenticateResponseOAuthToken.php new file mode 100644 index 00000000..3f60999b --- /dev/null +++ b/lib/Resource/AuthenticateResponseOAuthToken.php @@ -0,0 +1,52 @@ + + */ + public array $scopes, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + provider: $data['provider'], + refreshToken: $data['refresh_token'], + accessToken: $data['access_token'], + expiresAt: $data['expires_at'], + scopes: $data['scopes'], + ); + } + + public function toArray(): array + { + return [ + 'provider' => $this->provider, + 'refresh_token' => $this->refreshToken, + 'access_token' => $this->accessToken, + 'expires_at' => $this->expiresAt, + 'scopes' => $this->scopes, + ]; + } +} diff --git a/lib/Resource/AuthenticationChallenge.php b/lib/Resource/AuthenticationChallenge.php new file mode 100644 index 00000000..f7138b3a --- /dev/null +++ b/lib/Resource/AuthenticationChallenge.php @@ -0,0 +1,56 @@ + $this->object, + 'id' => $this->id, + 'authentication_factor_id' => $this->authenticationFactorId, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'expires_at' => $this->expiresAt?->format(\DateTimeInterface::RFC3339_EXTENDED), + 'code' => $this->code, + ]; + } +} diff --git a/lib/Resource/AuthenticationChallengeSms.php b/lib/Resource/AuthenticationChallengeSms.php deleted file mode 100644 index fdbe6fd8..00000000 --- a/lib/Resource/AuthenticationChallengeSms.php +++ /dev/null @@ -1,29 +0,0 @@ - "object", - "id" => "id", - "created_at" => "createdAt", - "updated_at" => "updatedAt", - "expires_at" => "expiresAt", - "authentication_factor_id" => "authenticationFactorId" - ]; -} diff --git a/lib/Resource/AuthenticationChallengeTotp.php b/lib/Resource/AuthenticationChallengeTotp.php deleted file mode 100644 index bbaa841d..00000000 --- a/lib/Resource/AuthenticationChallengeTotp.php +++ /dev/null @@ -1,29 +0,0 @@ - "object", - "id" => "id", - "created_at" => "createdAt", - "updated_at" => "updatedAt", - "expires_at" => "expiresAt", - "authentication_factor_id" => "authenticationFactorId" - ]; -} diff --git a/lib/Resource/AuthenticationChallengeVerifyResponse.php b/lib/Resource/AuthenticationChallengeVerifyResponse.php new file mode 100644 index 00000000..cf9cce77 --- /dev/null +++ b/lib/Resource/AuthenticationChallengeVerifyResponse.php @@ -0,0 +1,36 @@ + $this->challenge->toArray(), + 'valid' => $this->valid, + ]; + } +} diff --git a/lib/Resource/AuthenticationChallengesVerifyRequest.php b/lib/Resource/AuthenticationChallengesVerifyRequest.php new file mode 100644 index 00000000..3e2ccf67 --- /dev/null +++ b/lib/Resource/AuthenticationChallengesVerifyRequest.php @@ -0,0 +1,32 @@ + $this->code, + ]; + } +} diff --git a/lib/Resource/AuthenticationEmailVerificationFailed.php b/lib/Resource/AuthenticationEmailVerificationFailed.php new file mode 100644 index 00000000..f260f6a2 --- /dev/null +++ b/lib/Resource/AuthenticationEmailVerificationFailed.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationEmailVerificationFailedContext.php b/lib/Resource/AuthenticationEmailVerificationFailedContext.php new file mode 100644 index 00000000..67a7fcb3 --- /dev/null +++ b/lib/Resource/AuthenticationEmailVerificationFailedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?AuthenticationEmailVerificationFailedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? AuthenticationEmailVerificationFailedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/AuthenticationEmailVerificationFailedContextActor.php b/lib/Resource/AuthenticationEmailVerificationFailedContextActor.php new file mode 100644 index 00000000..eb67c965 --- /dev/null +++ b/lib/Resource/AuthenticationEmailVerificationFailedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/AuthenticationEmailVerificationFailedContextGoogleAnalyticsSession.php b/lib/Resource/AuthenticationEmailVerificationFailedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..a390c0f3 --- /dev/null +++ b/lib/Resource/AuthenticationEmailVerificationFailedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/AuthenticationEmailVerificationFailedData.php b/lib/Resource/AuthenticationEmailVerificationFailedData.php new file mode 100644 index 00000000..e5832240 --- /dev/null +++ b/lib/Resource/AuthenticationEmailVerificationFailedData.php @@ -0,0 +1,55 @@ + $this->type, + 'status' => $this->status, + 'ip_address' => $this->ipAddress, + 'user_agent' => $this->userAgent, + 'user_id' => $this->userId, + 'email' => $this->email, + 'error' => $this->error->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationEmailVerificationFailedDataError.php b/lib/Resource/AuthenticationEmailVerificationFailedDataError.php new file mode 100644 index 00000000..c3671d5b --- /dev/null +++ b/lib/Resource/AuthenticationEmailVerificationFailedDataError.php @@ -0,0 +1,37 @@ + $this->code, + 'message' => $this->message, + ]; + } +} diff --git a/lib/Resource/AuthenticationEmailVerificationSucceeded.php b/lib/Resource/AuthenticationEmailVerificationSucceeded.php new file mode 100644 index 00000000..3dba101d --- /dev/null +++ b/lib/Resource/AuthenticationEmailVerificationSucceeded.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationEmailVerificationSucceededContext.php b/lib/Resource/AuthenticationEmailVerificationSucceededContext.php new file mode 100644 index 00000000..5dfc2dc6 --- /dev/null +++ b/lib/Resource/AuthenticationEmailVerificationSucceededContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?AuthenticationEmailVerificationSucceededContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? AuthenticationEmailVerificationSucceededContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/AuthenticationEmailVerificationSucceededContextActor.php b/lib/Resource/AuthenticationEmailVerificationSucceededContextActor.php new file mode 100644 index 00000000..64e94c66 --- /dev/null +++ b/lib/Resource/AuthenticationEmailVerificationSucceededContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/AuthenticationEmailVerificationSucceededContextGoogleAnalyticsSession.php b/lib/Resource/AuthenticationEmailVerificationSucceededContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..de379046 --- /dev/null +++ b/lib/Resource/AuthenticationEmailVerificationSucceededContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/AuthenticationEmailVerificationSucceededData.php b/lib/Resource/AuthenticationEmailVerificationSucceededData.php new file mode 100644 index 00000000..2fb4d73d --- /dev/null +++ b/lib/Resource/AuthenticationEmailVerificationSucceededData.php @@ -0,0 +1,51 @@ + $this->type, + 'status' => $this->status, + 'ip_address' => $this->ipAddress, + 'user_agent' => $this->userAgent, + 'user_id' => $this->userId, + 'email' => $this->email, + ]; + } +} diff --git a/lib/Resource/AuthenticationFactor.php b/lib/Resource/AuthenticationFactor.php new file mode 100644 index 00000000..3ee2aeb3 --- /dev/null +++ b/lib/Resource/AuthenticationFactor.php @@ -0,0 +1,60 @@ + $this->object, + 'id' => $this->id, + 'type' => $this->type->value, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'user_id' => $this->userId, + 'sms' => $this->sms?->toArray(), + 'totp' => $this->totp?->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationFactorAndChallengeTotp.php b/lib/Resource/AuthenticationFactorAndChallengeTotp.php deleted file mode 100644 index f0b78687..00000000 --- a/lib/Resource/AuthenticationFactorAndChallengeTotp.php +++ /dev/null @@ -1,31 +0,0 @@ - "authenticationFactor", - "authentication_challenge" => "authenticationChallenge" - ]; - - public static function constructFromResponse($response) - { - $instance = parent::constructFromResponse($response); - $instance->values["authenticationFactor"] = AuthenticationFactorTotp::constructFromResponse($response["authentication_factor"]); - $instance->values["authenticationChallenge"] = AuthenticationChallengeTotp::constructFromResponse($response["authentication_challenge"]); - - return $instance; - } -} diff --git a/lib/Resource/AuthenticationFactorEnrolled.php b/lib/Resource/AuthenticationFactorEnrolled.php new file mode 100644 index 00000000..a338ac40 --- /dev/null +++ b/lib/Resource/AuthenticationFactorEnrolled.php @@ -0,0 +1,60 @@ + $this->object, + 'id' => $this->id, + 'type' => $this->type->value, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'user_id' => $this->userId, + 'sms' => $this->sms?->toArray(), + 'totp' => $this->totp?->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationFactorEnrolledSms.php b/lib/Resource/AuthenticationFactorEnrolledSms.php new file mode 100644 index 00000000..b56bf64a --- /dev/null +++ b/lib/Resource/AuthenticationFactorEnrolledSms.php @@ -0,0 +1,33 @@ + $this->phoneNumber, + ]; + } +} diff --git a/lib/Resource/AuthenticationFactorEnrolledTotp.php b/lib/Resource/AuthenticationFactorEnrolledTotp.php new file mode 100644 index 00000000..4c8ad17e --- /dev/null +++ b/lib/Resource/AuthenticationFactorEnrolledTotp.php @@ -0,0 +1,49 @@ + $this->issuer, + 'user' => $this->user, + 'secret' => $this->secret, + 'qr_code' => $this->qrCode, + 'uri' => $this->uri, + ]; + } +} diff --git a/lib/Resource/AuthenticationFactorEnrolledType.php b/lib/Resource/AuthenticationFactorEnrolledType.php new file mode 100644 index 00000000..43aa842d --- /dev/null +++ b/lib/Resource/AuthenticationFactorEnrolledType.php @@ -0,0 +1,15 @@ + "object", - "id" => "id", - "created_at" => "createdAt", - "updated_at" => "updatedAt", - "type" => "type", - "sms" => "sms" - ]; + public function toArray(): array + { + return [ + 'phone_number' => $this->phoneNumber, + ]; + } } diff --git a/lib/Resource/AuthenticationFactorTotp.php b/lib/Resource/AuthenticationFactorTotp.php index 5e0d8905..c6c619ef 100644 --- a/lib/Resource/AuthenticationFactorTotp.php +++ b/lib/Resource/AuthenticationFactorTotp.php @@ -1,29 +1,37 @@ "object", - "id" => "id", - "created_at" => "createdAt", - "updated_at" => "updatedAt", - "type" => "type", - "totp" => "totp" - ]; + public function toArray(): array + { + return [ + 'issuer' => $this->issuer, + 'user' => $this->user, + ]; + } } diff --git a/lib/Resource/AuthenticationFactorType.php b/lib/Resource/AuthenticationFactorType.php new file mode 100644 index 00000000..1c66f8ec --- /dev/null +++ b/lib/Resource/AuthenticationFactorType.php @@ -0,0 +1,15 @@ + $this->type->value, + 'phone_number' => $this->phoneNumber, + 'totp_issuer' => $this->totpIssuer, + 'totp_user' => $this->totpUser, + 'user_id' => $this->userId, + ]; + } +} diff --git a/lib/Resource/AuthenticationFactorsCreateRequestType.php b/lib/Resource/AuthenticationFactorsCreateRequestType.php new file mode 100644 index 00000000..200e365b --- /dev/null +++ b/lib/Resource/AuthenticationFactorsCreateRequestType.php @@ -0,0 +1,14 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationMFAFailedContext.php b/lib/Resource/AuthenticationMFAFailedContext.php new file mode 100644 index 00000000..6f6bb989 --- /dev/null +++ b/lib/Resource/AuthenticationMFAFailedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?AuthenticationMFAFailedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? AuthenticationMFAFailedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/AuthenticationMFAFailedContextActor.php b/lib/Resource/AuthenticationMFAFailedContextActor.php new file mode 100644 index 00000000..e8649aa3 --- /dev/null +++ b/lib/Resource/AuthenticationMFAFailedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/AuthenticationMFAFailedContextGoogleAnalyticsSession.php b/lib/Resource/AuthenticationMFAFailedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..3a215ba5 --- /dev/null +++ b/lib/Resource/AuthenticationMFAFailedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/AuthenticationMFAFailedData.php b/lib/Resource/AuthenticationMFAFailedData.php new file mode 100644 index 00000000..62e2bdee --- /dev/null +++ b/lib/Resource/AuthenticationMFAFailedData.php @@ -0,0 +1,55 @@ + $this->type, + 'status' => $this->status, + 'ip_address' => $this->ipAddress, + 'user_agent' => $this->userAgent, + 'user_id' => $this->userId, + 'email' => $this->email, + 'error' => $this->error->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationMFAFailedDataError.php b/lib/Resource/AuthenticationMFAFailedDataError.php new file mode 100644 index 00000000..51225463 --- /dev/null +++ b/lib/Resource/AuthenticationMFAFailedDataError.php @@ -0,0 +1,37 @@ + $this->code, + 'message' => $this->message, + ]; + } +} diff --git a/lib/Resource/AuthenticationMFASucceeded.php b/lib/Resource/AuthenticationMFASucceeded.php new file mode 100644 index 00000000..2f2c902a --- /dev/null +++ b/lib/Resource/AuthenticationMFASucceeded.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationMFASucceededContext.php b/lib/Resource/AuthenticationMFASucceededContext.php new file mode 100644 index 00000000..f70c8085 --- /dev/null +++ b/lib/Resource/AuthenticationMFASucceededContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?AuthenticationMFASucceededContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? AuthenticationMFASucceededContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/AuthenticationMFASucceededContextActor.php b/lib/Resource/AuthenticationMFASucceededContextActor.php new file mode 100644 index 00000000..540b21fb --- /dev/null +++ b/lib/Resource/AuthenticationMFASucceededContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/AuthenticationMFASucceededContextGoogleAnalyticsSession.php b/lib/Resource/AuthenticationMFASucceededContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..4cff0aae --- /dev/null +++ b/lib/Resource/AuthenticationMFASucceededContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/AuthenticationMFASucceededData.php b/lib/Resource/AuthenticationMFASucceededData.php new file mode 100644 index 00000000..cf9266df --- /dev/null +++ b/lib/Resource/AuthenticationMFASucceededData.php @@ -0,0 +1,51 @@ + $this->type, + 'status' => $this->status, + 'ip_address' => $this->ipAddress, + 'user_agent' => $this->userAgent, + 'user_id' => $this->userId, + 'email' => $this->email, + ]; + } +} diff --git a/lib/Resource/AuthenticationMagicAuthFailed.php b/lib/Resource/AuthenticationMagicAuthFailed.php new file mode 100644 index 00000000..9980c972 --- /dev/null +++ b/lib/Resource/AuthenticationMagicAuthFailed.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationMagicAuthFailedContext.php b/lib/Resource/AuthenticationMagicAuthFailedContext.php new file mode 100644 index 00000000..f62472e8 --- /dev/null +++ b/lib/Resource/AuthenticationMagicAuthFailedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?AuthenticationMagicAuthFailedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? AuthenticationMagicAuthFailedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/AuthenticationMagicAuthFailedContextActor.php b/lib/Resource/AuthenticationMagicAuthFailedContextActor.php new file mode 100644 index 00000000..7c5c7096 --- /dev/null +++ b/lib/Resource/AuthenticationMagicAuthFailedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/AuthenticationMagicAuthFailedContextGoogleAnalyticsSession.php b/lib/Resource/AuthenticationMagicAuthFailedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..1441869c --- /dev/null +++ b/lib/Resource/AuthenticationMagicAuthFailedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/AuthenticationMagicAuthFailedData.php b/lib/Resource/AuthenticationMagicAuthFailedData.php new file mode 100644 index 00000000..a6e8fbf5 --- /dev/null +++ b/lib/Resource/AuthenticationMagicAuthFailedData.php @@ -0,0 +1,55 @@ + $this->type, + 'status' => $this->status, + 'ip_address' => $this->ipAddress, + 'user_agent' => $this->userAgent, + 'user_id' => $this->userId, + 'email' => $this->email, + 'error' => $this->error->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationMagicAuthFailedDataError.php b/lib/Resource/AuthenticationMagicAuthFailedDataError.php new file mode 100644 index 00000000..76364b18 --- /dev/null +++ b/lib/Resource/AuthenticationMagicAuthFailedDataError.php @@ -0,0 +1,37 @@ + $this->code, + 'message' => $this->message, + ]; + } +} diff --git a/lib/Resource/AuthenticationMagicAuthSucceeded.php b/lib/Resource/AuthenticationMagicAuthSucceeded.php new file mode 100644 index 00000000..6054f182 --- /dev/null +++ b/lib/Resource/AuthenticationMagicAuthSucceeded.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationMagicAuthSucceededContext.php b/lib/Resource/AuthenticationMagicAuthSucceededContext.php new file mode 100644 index 00000000..b39f50ff --- /dev/null +++ b/lib/Resource/AuthenticationMagicAuthSucceededContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?AuthenticationMagicAuthSucceededContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? AuthenticationMagicAuthSucceededContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/AuthenticationMagicAuthSucceededContextActor.php b/lib/Resource/AuthenticationMagicAuthSucceededContextActor.php new file mode 100644 index 00000000..42645ca8 --- /dev/null +++ b/lib/Resource/AuthenticationMagicAuthSucceededContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/AuthenticationMagicAuthSucceededContextGoogleAnalyticsSession.php b/lib/Resource/AuthenticationMagicAuthSucceededContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..a38d39c2 --- /dev/null +++ b/lib/Resource/AuthenticationMagicAuthSucceededContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/AuthenticationMagicAuthSucceededData.php b/lib/Resource/AuthenticationMagicAuthSucceededData.php new file mode 100644 index 00000000..ed02634a --- /dev/null +++ b/lib/Resource/AuthenticationMagicAuthSucceededData.php @@ -0,0 +1,51 @@ + $this->type, + 'status' => $this->status, + 'ip_address' => $this->ipAddress, + 'user_agent' => $this->userAgent, + 'user_id' => $this->userId, + 'email' => $this->email, + ]; + } +} diff --git a/lib/Resource/AuthenticationOAuthFailed.php b/lib/Resource/AuthenticationOAuthFailed.php new file mode 100644 index 00000000..cadf7652 --- /dev/null +++ b/lib/Resource/AuthenticationOAuthFailed.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationOAuthFailedContext.php b/lib/Resource/AuthenticationOAuthFailedContext.php new file mode 100644 index 00000000..c8c63dee --- /dev/null +++ b/lib/Resource/AuthenticationOAuthFailedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?AuthenticationOAuthFailedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? AuthenticationOAuthFailedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/AuthenticationOAuthFailedContextActor.php b/lib/Resource/AuthenticationOAuthFailedContextActor.php new file mode 100644 index 00000000..bfb875af --- /dev/null +++ b/lib/Resource/AuthenticationOAuthFailedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/AuthenticationOAuthFailedContextGoogleAnalyticsSession.php b/lib/Resource/AuthenticationOAuthFailedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..4167d209 --- /dev/null +++ b/lib/Resource/AuthenticationOAuthFailedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/AuthenticationOAuthFailedData.php b/lib/Resource/AuthenticationOAuthFailedData.php new file mode 100644 index 00000000..e2186733 --- /dev/null +++ b/lib/Resource/AuthenticationOAuthFailedData.php @@ -0,0 +1,55 @@ + $this->type, + 'status' => $this->status, + 'ip_address' => $this->ipAddress, + 'user_agent' => $this->userAgent, + 'user_id' => $this->userId, + 'email' => $this->email, + 'error' => $this->error->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationOAuthFailedDataError.php b/lib/Resource/AuthenticationOAuthFailedDataError.php new file mode 100644 index 00000000..fea47805 --- /dev/null +++ b/lib/Resource/AuthenticationOAuthFailedDataError.php @@ -0,0 +1,37 @@ + $this->code, + 'message' => $this->message, + ]; + } +} diff --git a/lib/Resource/AuthenticationOAuthSucceeded.php b/lib/Resource/AuthenticationOAuthSucceeded.php new file mode 100644 index 00000000..1d8aaa55 --- /dev/null +++ b/lib/Resource/AuthenticationOAuthSucceeded.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationOAuthSucceededContext.php b/lib/Resource/AuthenticationOAuthSucceededContext.php new file mode 100644 index 00000000..2b8b0e03 --- /dev/null +++ b/lib/Resource/AuthenticationOAuthSucceededContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?AuthenticationOAuthSucceededContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? AuthenticationOAuthSucceededContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/AuthenticationOAuthSucceededContextActor.php b/lib/Resource/AuthenticationOAuthSucceededContextActor.php new file mode 100644 index 00000000..0f7b426a --- /dev/null +++ b/lib/Resource/AuthenticationOAuthSucceededContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/AuthenticationOAuthSucceededContextGoogleAnalyticsSession.php b/lib/Resource/AuthenticationOAuthSucceededContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..e7811f18 --- /dev/null +++ b/lib/Resource/AuthenticationOAuthSucceededContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/AuthenticationOAuthSucceededData.php b/lib/Resource/AuthenticationOAuthSucceededData.php new file mode 100644 index 00000000..2343857f --- /dev/null +++ b/lib/Resource/AuthenticationOAuthSucceededData.php @@ -0,0 +1,51 @@ + $this->type, + 'status' => $this->status, + 'ip_address' => $this->ipAddress, + 'user_agent' => $this->userAgent, + 'user_id' => $this->userId, + 'email' => $this->email, + ]; + } +} diff --git a/lib/Resource/AuthenticationPasskeyFailed.php b/lib/Resource/AuthenticationPasskeyFailed.php new file mode 100644 index 00000000..2afddfff --- /dev/null +++ b/lib/Resource/AuthenticationPasskeyFailed.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationPasskeyFailedContext.php b/lib/Resource/AuthenticationPasskeyFailedContext.php new file mode 100644 index 00000000..bcd240bf --- /dev/null +++ b/lib/Resource/AuthenticationPasskeyFailedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?AuthenticationPasskeyFailedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? AuthenticationPasskeyFailedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/AuthenticationPasskeyFailedContextActor.php b/lib/Resource/AuthenticationPasskeyFailedContextActor.php new file mode 100644 index 00000000..c928a2e9 --- /dev/null +++ b/lib/Resource/AuthenticationPasskeyFailedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/AuthenticationPasskeyFailedContextGoogleAnalyticsSession.php b/lib/Resource/AuthenticationPasskeyFailedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..5f4e96fd --- /dev/null +++ b/lib/Resource/AuthenticationPasskeyFailedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/AuthenticationPasskeyFailedData.php b/lib/Resource/AuthenticationPasskeyFailedData.php new file mode 100644 index 00000000..7ee389a0 --- /dev/null +++ b/lib/Resource/AuthenticationPasskeyFailedData.php @@ -0,0 +1,55 @@ + $this->type, + 'status' => $this->status, + 'ip_address' => $this->ipAddress, + 'user_agent' => $this->userAgent, + 'user_id' => $this->userId, + 'email' => $this->email, + 'error' => $this->error->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationPasskeyFailedDataError.php b/lib/Resource/AuthenticationPasskeyFailedDataError.php new file mode 100644 index 00000000..25a9e888 --- /dev/null +++ b/lib/Resource/AuthenticationPasskeyFailedDataError.php @@ -0,0 +1,37 @@ + $this->code, + 'message' => $this->message, + ]; + } +} diff --git a/lib/Resource/AuthenticationPasskeySucceeded.php b/lib/Resource/AuthenticationPasskeySucceeded.php new file mode 100644 index 00000000..5b42afc6 --- /dev/null +++ b/lib/Resource/AuthenticationPasskeySucceeded.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationPasskeySucceededContext.php b/lib/Resource/AuthenticationPasskeySucceededContext.php new file mode 100644 index 00000000..e3a91e4a --- /dev/null +++ b/lib/Resource/AuthenticationPasskeySucceededContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?AuthenticationPasskeySucceededContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? AuthenticationPasskeySucceededContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/AuthenticationPasskeySucceededContextActor.php b/lib/Resource/AuthenticationPasskeySucceededContextActor.php new file mode 100644 index 00000000..2c0472b5 --- /dev/null +++ b/lib/Resource/AuthenticationPasskeySucceededContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/AuthenticationPasskeySucceededContextGoogleAnalyticsSession.php b/lib/Resource/AuthenticationPasskeySucceededContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..b4397d57 --- /dev/null +++ b/lib/Resource/AuthenticationPasskeySucceededContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/AuthenticationPasskeySucceededData.php b/lib/Resource/AuthenticationPasskeySucceededData.php new file mode 100644 index 00000000..0e066dd7 --- /dev/null +++ b/lib/Resource/AuthenticationPasskeySucceededData.php @@ -0,0 +1,51 @@ + $this->type, + 'status' => $this->status, + 'ip_address' => $this->ipAddress, + 'user_agent' => $this->userAgent, + 'user_id' => $this->userId, + 'email' => $this->email, + ]; + } +} diff --git a/lib/Resource/AuthenticationPasswordFailed.php b/lib/Resource/AuthenticationPasswordFailed.php new file mode 100644 index 00000000..5dca79d2 --- /dev/null +++ b/lib/Resource/AuthenticationPasswordFailed.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationPasswordFailedContext.php b/lib/Resource/AuthenticationPasswordFailedContext.php new file mode 100644 index 00000000..7ed3bd5a --- /dev/null +++ b/lib/Resource/AuthenticationPasswordFailedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?AuthenticationPasswordFailedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? AuthenticationPasswordFailedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/AuthenticationPasswordFailedContextActor.php b/lib/Resource/AuthenticationPasswordFailedContextActor.php new file mode 100644 index 00000000..24a5e0b1 --- /dev/null +++ b/lib/Resource/AuthenticationPasswordFailedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/AuthenticationPasswordFailedContextGoogleAnalyticsSession.php b/lib/Resource/AuthenticationPasswordFailedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..f4d16273 --- /dev/null +++ b/lib/Resource/AuthenticationPasswordFailedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/AuthenticationPasswordFailedData.php b/lib/Resource/AuthenticationPasswordFailedData.php new file mode 100644 index 00000000..c8112be1 --- /dev/null +++ b/lib/Resource/AuthenticationPasswordFailedData.php @@ -0,0 +1,55 @@ + $this->type, + 'status' => $this->status, + 'ip_address' => $this->ipAddress, + 'user_agent' => $this->userAgent, + 'user_id' => $this->userId, + 'email' => $this->email, + 'error' => $this->error->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationPasswordFailedDataError.php b/lib/Resource/AuthenticationPasswordFailedDataError.php new file mode 100644 index 00000000..6a2070b1 --- /dev/null +++ b/lib/Resource/AuthenticationPasswordFailedDataError.php @@ -0,0 +1,37 @@ + $this->code, + 'message' => $this->message, + ]; + } +} diff --git a/lib/Resource/AuthenticationPasswordSucceeded.php b/lib/Resource/AuthenticationPasswordSucceeded.php new file mode 100644 index 00000000..f1de81d3 --- /dev/null +++ b/lib/Resource/AuthenticationPasswordSucceeded.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationPasswordSucceededContext.php b/lib/Resource/AuthenticationPasswordSucceededContext.php new file mode 100644 index 00000000..1b401f1d --- /dev/null +++ b/lib/Resource/AuthenticationPasswordSucceededContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?AuthenticationPasswordSucceededContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? AuthenticationPasswordSucceededContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/AuthenticationPasswordSucceededContextActor.php b/lib/Resource/AuthenticationPasswordSucceededContextActor.php new file mode 100644 index 00000000..3656e9a2 --- /dev/null +++ b/lib/Resource/AuthenticationPasswordSucceededContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/AuthenticationPasswordSucceededContextGoogleAnalyticsSession.php b/lib/Resource/AuthenticationPasswordSucceededContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..ebd25a74 --- /dev/null +++ b/lib/Resource/AuthenticationPasswordSucceededContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/AuthenticationPasswordSucceededData.php b/lib/Resource/AuthenticationPasswordSucceededData.php new file mode 100644 index 00000000..54b1a038 --- /dev/null +++ b/lib/Resource/AuthenticationPasswordSucceededData.php @@ -0,0 +1,51 @@ + $this->type, + 'status' => $this->status, + 'ip_address' => $this->ipAddress, + 'user_agent' => $this->userAgent, + 'user_id' => $this->userId, + 'email' => $this->email, + ]; + } +} diff --git a/lib/Resource/AuthenticationRadarRiskDetected.php b/lib/Resource/AuthenticationRadarRiskDetected.php new file mode 100644 index 00000000..717da809 --- /dev/null +++ b/lib/Resource/AuthenticationRadarRiskDetected.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationRadarRiskDetectedContext.php b/lib/Resource/AuthenticationRadarRiskDetectedContext.php new file mode 100644 index 00000000..afc77d88 --- /dev/null +++ b/lib/Resource/AuthenticationRadarRiskDetectedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?AuthenticationRadarRiskDetectedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? AuthenticationRadarRiskDetectedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/AuthenticationRadarRiskDetectedContextActor.php b/lib/Resource/AuthenticationRadarRiskDetectedContextActor.php new file mode 100644 index 00000000..d8332869 --- /dev/null +++ b/lib/Resource/AuthenticationRadarRiskDetectedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/AuthenticationRadarRiskDetectedContextGoogleAnalyticsSession.php b/lib/Resource/AuthenticationRadarRiskDetectedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..8edfe26e --- /dev/null +++ b/lib/Resource/AuthenticationRadarRiskDetectedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/AuthenticationRadarRiskDetectedData.php b/lib/Resource/AuthenticationRadarRiskDetectedData.php new file mode 100644 index 00000000..df9a4cbb --- /dev/null +++ b/lib/Resource/AuthenticationRadarRiskDetectedData.php @@ -0,0 +1,60 @@ + $this->authMethod, + 'action' => $this->action->value, + 'control' => $this->control, + 'blocklist_type' => $this->blocklistType, + 'ip_address' => $this->ipAddress, + 'user_agent' => $this->userAgent, + 'user_id' => $this->userId, + 'email' => $this->email, + ]; + } +} diff --git a/lib/Resource/AuthenticationRadarRiskDetectedDataAction.php b/lib/Resource/AuthenticationRadarRiskDetectedDataAction.php new file mode 100644 index 00000000..19ac7655 --- /dev/null +++ b/lib/Resource/AuthenticationRadarRiskDetectedDataAction.php @@ -0,0 +1,13 @@ + "organizationId", - "access_token" => "accessToken", - "refresh_token" => "refreshToken", - "oauth_tokens" => "oauthTokens", - ]; - - public static function constructFromResponse($response) - { - $instance = parent::constructFromResponse($response); - - $instance->values["user"] = User::constructFromResponse($response["user"]); - - if (isset($response["impersonator"])) { - $instance->values["impersonator"] = Impersonator::constructFromResponse( - $response["impersonator"] - ); - } - - if (isset($response["oauth_tokens"])) { - $instance->values["oauthTokens"] = OAuthTokens::constructFromResponse($response["oauth_tokens"]); - } - - return $instance; - } -} diff --git a/lib/Resource/AuthenticationSSOFailed.php b/lib/Resource/AuthenticationSSOFailed.php new file mode 100644 index 00000000..b0b61d7e --- /dev/null +++ b/lib/Resource/AuthenticationSSOFailed.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationSSOFailedContext.php b/lib/Resource/AuthenticationSSOFailedContext.php new file mode 100644 index 00000000..32bdc0dd --- /dev/null +++ b/lib/Resource/AuthenticationSSOFailedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?AuthenticationSSOFailedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? AuthenticationSSOFailedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/AuthenticationSSOFailedContextActor.php b/lib/Resource/AuthenticationSSOFailedContextActor.php new file mode 100644 index 00000000..9c5d4fbf --- /dev/null +++ b/lib/Resource/AuthenticationSSOFailedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/AuthenticationSSOFailedContextGoogleAnalyticsSession.php b/lib/Resource/AuthenticationSSOFailedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..e6c4a6c5 --- /dev/null +++ b/lib/Resource/AuthenticationSSOFailedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/AuthenticationSSOFailedData.php b/lib/Resource/AuthenticationSSOFailedData.php new file mode 100644 index 00000000..09fb5129 --- /dev/null +++ b/lib/Resource/AuthenticationSSOFailedData.php @@ -0,0 +1,59 @@ + $this->type, + 'status' => $this->status, + 'ip_address' => $this->ipAddress, + 'user_agent' => $this->userAgent, + 'user_id' => $this->userId, + 'email' => $this->email, + 'sso' => $this->sso->toArray(), + 'error' => $this->error->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationSSOFailedDataError.php b/lib/Resource/AuthenticationSSOFailedDataError.php new file mode 100644 index 00000000..d9a7c45a --- /dev/null +++ b/lib/Resource/AuthenticationSSOFailedDataError.php @@ -0,0 +1,37 @@ + $this->code, + 'message' => $this->message, + ]; + } +} diff --git a/lib/Resource/AuthenticationSSOFailedDataSSO.php b/lib/Resource/AuthenticationSSOFailedDataSSO.php new file mode 100644 index 00000000..91cdb636 --- /dev/null +++ b/lib/Resource/AuthenticationSSOFailedDataSSO.php @@ -0,0 +1,41 @@ + $this->organizationId, + 'connection_id' => $this->connectionId, + 'session_id' => $this->sessionId, + ]; + } +} diff --git a/lib/Resource/AuthenticationSSOStarted.php b/lib/Resource/AuthenticationSSOStarted.php new file mode 100644 index 00000000..0522b299 --- /dev/null +++ b/lib/Resource/AuthenticationSSOStarted.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationSSOStartedContext.php b/lib/Resource/AuthenticationSSOStartedContext.php new file mode 100644 index 00000000..7a349a4b --- /dev/null +++ b/lib/Resource/AuthenticationSSOStartedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?AuthenticationSSOStartedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? AuthenticationSSOStartedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/AuthenticationSSOStartedContextActor.php b/lib/Resource/AuthenticationSSOStartedContextActor.php new file mode 100644 index 00000000..7267c1bc --- /dev/null +++ b/lib/Resource/AuthenticationSSOStartedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/AuthenticationSSOStartedContextGoogleAnalyticsSession.php b/lib/Resource/AuthenticationSSOStartedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..05cba820 --- /dev/null +++ b/lib/Resource/AuthenticationSSOStartedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/AuthenticationSSOStartedData.php b/lib/Resource/AuthenticationSSOStartedData.php new file mode 100644 index 00000000..21b25c26 --- /dev/null +++ b/lib/Resource/AuthenticationSSOStartedData.php @@ -0,0 +1,55 @@ + $this->type, + 'status' => $this->status, + 'ip_address' => $this->ipAddress, + 'user_agent' => $this->userAgent, + 'user_id' => $this->userId, + 'email' => $this->email, + 'sso' => $this->sso->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationSSOStartedDataSSO.php b/lib/Resource/AuthenticationSSOStartedDataSSO.php new file mode 100644 index 00000000..4ece50ce --- /dev/null +++ b/lib/Resource/AuthenticationSSOStartedDataSSO.php @@ -0,0 +1,41 @@ + $this->organizationId, + 'connection_id' => $this->connectionId, + 'session_id' => $this->sessionId, + ]; + } +} diff --git a/lib/Resource/AuthenticationSSOSucceeded.php b/lib/Resource/AuthenticationSSOSucceeded.php new file mode 100644 index 00000000..13c7697e --- /dev/null +++ b/lib/Resource/AuthenticationSSOSucceeded.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationSSOSucceededContext.php b/lib/Resource/AuthenticationSSOSucceededContext.php new file mode 100644 index 00000000..86132620 --- /dev/null +++ b/lib/Resource/AuthenticationSSOSucceededContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?AuthenticationSSOSucceededContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? AuthenticationSSOSucceededContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/AuthenticationSSOSucceededContextActor.php b/lib/Resource/AuthenticationSSOSucceededContextActor.php new file mode 100644 index 00000000..79acf744 --- /dev/null +++ b/lib/Resource/AuthenticationSSOSucceededContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/AuthenticationSSOSucceededContextGoogleAnalyticsSession.php b/lib/Resource/AuthenticationSSOSucceededContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..ca9bee21 --- /dev/null +++ b/lib/Resource/AuthenticationSSOSucceededContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/AuthenticationSSOSucceededData.php b/lib/Resource/AuthenticationSSOSucceededData.php new file mode 100644 index 00000000..7e53f65b --- /dev/null +++ b/lib/Resource/AuthenticationSSOSucceededData.php @@ -0,0 +1,55 @@ + $this->type, + 'status' => $this->status, + 'ip_address' => $this->ipAddress, + 'user_agent' => $this->userAgent, + 'user_id' => $this->userId, + 'email' => $this->email, + 'sso' => $this->sso->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationSSOSucceededDataSSO.php b/lib/Resource/AuthenticationSSOSucceededDataSSO.php new file mode 100644 index 00000000..354d5f6f --- /dev/null +++ b/lib/Resource/AuthenticationSSOSucceededDataSSO.php @@ -0,0 +1,41 @@ + $this->organizationId, + 'connection_id' => $this->connectionId, + 'session_id' => $this->sessionId, + ]; + } +} diff --git a/lib/Resource/AuthenticationSSOTimedOut.php b/lib/Resource/AuthenticationSSOTimedOut.php new file mode 100644 index 00000000..53702c19 --- /dev/null +++ b/lib/Resource/AuthenticationSSOTimedOut.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationSSOTimedOutContext.php b/lib/Resource/AuthenticationSSOTimedOutContext.php new file mode 100644 index 00000000..44275d50 --- /dev/null +++ b/lib/Resource/AuthenticationSSOTimedOutContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?AuthenticationSSOTimedOutContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? AuthenticationSSOTimedOutContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/AuthenticationSSOTimedOutContextActor.php b/lib/Resource/AuthenticationSSOTimedOutContextActor.php new file mode 100644 index 00000000..774d78a8 --- /dev/null +++ b/lib/Resource/AuthenticationSSOTimedOutContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/AuthenticationSSOTimedOutContextGoogleAnalyticsSession.php b/lib/Resource/AuthenticationSSOTimedOutContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..8adeba9d --- /dev/null +++ b/lib/Resource/AuthenticationSSOTimedOutContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/AuthenticationSSOTimedOutData.php b/lib/Resource/AuthenticationSSOTimedOutData.php new file mode 100644 index 00000000..0ec25be1 --- /dev/null +++ b/lib/Resource/AuthenticationSSOTimedOutData.php @@ -0,0 +1,59 @@ + $this->type, + 'status' => $this->status, + 'ip_address' => $this->ipAddress, + 'user_agent' => $this->userAgent, + 'user_id' => $this->userId, + 'email' => $this->email, + 'sso' => $this->sso->toArray(), + 'error' => $this->error->toArray(), + ]; + } +} diff --git a/lib/Resource/AuthenticationSSOTimedOutDataError.php b/lib/Resource/AuthenticationSSOTimedOutDataError.php new file mode 100644 index 00000000..97400d5b --- /dev/null +++ b/lib/Resource/AuthenticationSSOTimedOutDataError.php @@ -0,0 +1,37 @@ + $this->code, + 'message' => $this->message, + ]; + } +} diff --git a/lib/Resource/AuthenticationSSOTimedOutDataSSO.php b/lib/Resource/AuthenticationSSOTimedOutDataSSO.php new file mode 100644 index 00000000..963d0413 --- /dev/null +++ b/lib/Resource/AuthenticationSSOTimedOutDataSSO.php @@ -0,0 +1,41 @@ + $this->organizationId, + 'connection_id' => $this->connectionId, + 'session_id' => $this->sessionId, + ]; + } +} diff --git a/lib/Resource/AuthorizationAssignment.php b/lib/Resource/AuthorizationAssignment.php new file mode 100644 index 00000000..068163ca --- /dev/null +++ b/lib/Resource/AuthorizationAssignment.php @@ -0,0 +1,13 @@ + $this->authorized, + ]; + } +} diff --git a/lib/Resource/AuthorizationCodeSessionAuthenticateRequest.php b/lib/Resource/AuthorizationCodeSessionAuthenticateRequest.php new file mode 100644 index 00000000..03aa4518 --- /dev/null +++ b/lib/Resource/AuthorizationCodeSessionAuthenticateRequest.php @@ -0,0 +1,55 @@ + $this->clientId, + 'client_secret' => $this->clientSecret, + 'grant_type' => $this->grantType, + 'code' => $this->code, + 'ip_address' => $this->ipAddress, + 'device_id' => $this->deviceId, + 'user_agent' => $this->userAgent, + ]; + } +} diff --git a/lib/Resource/AuthorizationOrder.php b/lib/Resource/AuthorizationOrder.php new file mode 100644 index 00000000..f8f5e6bd --- /dev/null +++ b/lib/Resource/AuthorizationOrder.php @@ -0,0 +1,14 @@ + $this->object, + 'id' => $this->id, + 'slug' => $this->slug, + 'name' => $this->name, + 'description' => $this->description, + 'system' => $this->system, + 'resource_type_slug' => $this->resourceTypeSlug, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/AuthorizationResource.php b/lib/Resource/AuthorizationResource.php new file mode 100644 index 00000000..e51aade5 --- /dev/null +++ b/lib/Resource/AuthorizationResource.php @@ -0,0 +1,68 @@ + $this->object, + 'name' => $this->name, + 'description' => $this->description, + 'organization_id' => $this->organizationId, + 'parent_resource_id' => $this->parentResourceId, + 'id' => $this->id, + 'external_id' => $this->externalId, + 'resource_type_slug' => $this->resourceTypeSlug, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/AuthorizedConnectApplicationListData.php b/lib/Resource/AuthorizedConnectApplicationListData.php new file mode 100644 index 00000000..8d8b449f --- /dev/null +++ b/lib/Resource/AuthorizedConnectApplicationListData.php @@ -0,0 +1,46 @@ + + */ + public array $grantedScopes, + public ConnectApplication $application, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + grantedScopes: $data['granted_scopes'], + application: ConnectApplication::fromArray($data['application']), + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'granted_scopes' => $this->grantedScopes, + 'application' => $this->application->toArray(), + ]; + } +} diff --git a/lib/Resource/BaseWorkOSResource.php b/lib/Resource/BaseWorkOSResource.php deleted file mode 100644 index 71b0a486..00000000 --- a/lib/Resource/BaseWorkOSResource.php +++ /dev/null @@ -1,106 +0,0 @@ - - */ - protected const RESPONSE_TO_RESOURCE_KEY = []; - - /** - * List of attributes available in this resource. - * Child classes should override this constant. - * - * @var array - */ - protected const RESOURCE_ATTRIBUTES = []; - - /** - * @var array $values; - */ - protected $values; - - /** - * @var array $raw; - */ - public $raw; - - private function __construct() - { - } - - /** - * Creates a Resource from a Response. - * - * @param array $response - * - * @return static - */ - public static function constructFromResponse($response) - { - $instance = new static(); - - $instance->raw = $response; - $instance->values = []; - - foreach (static::RESPONSE_TO_RESOURCE_KEY as $responseKey => $resourceKey) { - try { - $instance->values[$resourceKey] = $instance->raw[$responseKey] ?? null; - } catch (\OutOfBoundsException $e) { - $instance->values[$resourceKey] = null; - } - } - - return $instance; - } - - public function toArray() - { - return \array_reduce(static::RESOURCE_ATTRIBUTES, function ($arr, $key) { - $arr[$key] = $this->values[$key]; - return $arr; - }, []); - } - - /** - * Magic method overrides. - */ - public function __set($key, $value) - { - if (\in_array($key, static::RESOURCE_ATTRIBUTES)) { - $this->values[$key] = $value; - } - - $msg = "{$key} does not exist on " . static::class; - throw new \WorkOS\Exception\UnexpectedValueException($msg); - } - - public function __isset($key) - { - return isset($this->values[$key]); - } - - public function __unset($key) - { - unset($this->values[$key]); - } - - public function &__get($key) - { - if (\in_array($key, static::RESOURCE_ATTRIBUTES)) { - return $this->values[$key]; - } - - if (isset($this->raw[$key])) { - return $this->raw[$key]; - } - - $msg = "{$key} does not exist on " . static::class; - throw new \WorkOS\Exception\UnexpectedValueException($msg); - } -} diff --git a/lib/Resource/CORSOriginResponse.php b/lib/Resource/CORSOriginResponse.php new file mode 100644 index 00000000..7711ef87 --- /dev/null +++ b/lib/Resource/CORSOriginResponse.php @@ -0,0 +1,48 @@ + $this->object, + 'id' => $this->id, + 'origin' => $this->origin, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/ChallengeAuthenticationFactor.php b/lib/Resource/ChallengeAuthenticationFactor.php new file mode 100644 index 00000000..33622be0 --- /dev/null +++ b/lib/Resource/ChallengeAuthenticationFactor.php @@ -0,0 +1,32 @@ + $this->smsTemplate, + ]; + } +} diff --git a/lib/Resource/CheckAuthorization.php b/lib/Resource/CheckAuthorization.php new file mode 100644 index 00000000..19676936 --- /dev/null +++ b/lib/Resource/CheckAuthorization.php @@ -0,0 +1,44 @@ + $this->permissionSlug, + 'resource_id' => $this->resourceId, + 'resource_external_id' => $this->resourceExternalId, + 'resource_type_slug' => $this->resourceTypeSlug, + ]; + } +} diff --git a/lib/Resource/ConfirmEmailChange.php b/lib/Resource/ConfirmEmailChange.php new file mode 100644 index 00000000..b6fddf3d --- /dev/null +++ b/lib/Resource/ConfirmEmailChange.php @@ -0,0 +1,32 @@ + $this->code, + ]; + } +} diff --git a/lib/Resource/ConnectApplication.php b/lib/Resource/ConnectApplication.php new file mode 100644 index 00000000..a777cea5 --- /dev/null +++ b/lib/Resource/ConnectApplication.php @@ -0,0 +1,63 @@ + + */ + public array $scopes, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + clientId: $data['client_id'], + description: $data['description'] ?? null, + name: $data['name'], + scopes: $data['scopes'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'client_id' => $this->clientId, + 'description' => $this->description, + 'name' => $this->name, + 'scopes' => $this->scopes, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/ConnectedAccount.php b/lib/Resource/ConnectedAccount.php new file mode 100644 index 00000000..1d25aa68 --- /dev/null +++ b/lib/Resource/ConnectedAccount.php @@ -0,0 +1,68 @@ + + */ + public array $scopes, + /** + * The state of the connected account: + * - `connected`: The connection is active and tokens are valid. + * - `needs_reauthorization`: The user needs to reauthorize the connection, typically because required scopes have changed. + * - `disconnected`: The connection has been disconnected. + */ + public ConnectedAccountState $state, + /** The timestamp when the connection was created. */ + public string $createdAt, + /** The timestamp when the connection was last updated. */ + public string $updatedAt, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + userId: $data['user_id'] ?? null, + organizationId: $data['organization_id'] ?? null, + scopes: $data['scopes'], + state: ConnectedAccountState::from($data['state']), + createdAt: $data['created_at'], + updatedAt: $data['updated_at'], + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'user_id' => $this->userId, + 'organization_id' => $this->organizationId, + 'scopes' => $this->scopes, + 'state' => $this->state->value, + 'created_at' => $this->createdAt, + 'updated_at' => $this->updatedAt, + ]; + } +} diff --git a/lib/Resource/ConnectedAccountState.php b/lib/Resource/ConnectedAccountState.php new file mode 100644 index 00000000..2c18c9d4 --- /dev/null +++ b/lib/Resource/ConnectedAccountState.php @@ -0,0 +1,14 @@ + "id", - "state" => "state", - "status" => "status", - "name" => "name", - "connection_type" => "connectionType", - "organization_id" => "organizationId", - ]; + public function __construct( + /** Distinguishes the Connection object. */ + public string $object, + /** Unique identifier for the Connection. */ + public string $id, + /** The type of the SSO Connection used to authenticate the user. The Connection type may be used to dynamically generate authorization URLs. */ + public ConnectionType $connectionType, + /** A human-readable name for the Connection. This will most commonly be the organization's name. */ + public string $name, + /** Indicates whether a Connection is able to authenticate users. */ + public ConnectionState $state, + /** + * Deprecated. Use `state` instead. + * @deprecated + */ + public ConnectionStatus $status, + /** + * List of Organization Domains. + * @var array<\WorkOS\Resource\ConnectionDomain> + */ + public array $domains, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + /** Unique identifier for the Organization in which the Connection resides. */ + public ?string $organizationId = null, + /** Configuration options for SAML connections. Only present for SAML connection types. */ + public ?ConnectionOption $options = null, + ) { + } - public static function constructFromResponse($response) + public static function fromArray(array $data): self { - $instance = parent::constructFromResponse($response); - - $rawDomains = $response["domains"]; - $domains = []; - foreach ($rawDomains as $rawDomain) { - \array_push($domains, Domain::constructFromResponse($rawDomain)); - } - - $instance->values["domains"] = $domains; - - return $instance; + return new self( + object: $data['object'], + id: $data['id'], + connectionType: ConnectionType::from($data['connection_type']), + name: $data['name'], + state: ConnectionState::from($data['state']), + status: ConnectionStatus::from($data['status']), + domains: array_map(fn ($item) => ConnectionDomain::fromArray($item), $data['domains']), + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + organizationId: $data['organization_id'] ?? null, + options: isset($data['options']) ? ConnectionOption::fromArray($data['options']) : null, + ); } - public function toArray() + public function toArray(): array { - $connectionArray = parent::toArray(); - - $domains = []; - foreach ($connectionArray["domains"] as $domain) { - \array_push($domains, $domain->toArray()); - } - - $connectionArray["domains"] = $domains; - - return $connectionArray; + return [ + 'object' => $this->object, + 'id' => $this->id, + 'connection_type' => $this->connectionType->value, + 'name' => $this->name, + 'state' => $this->state->value, + 'status' => $this->status->value, + 'domains' => array_map(fn ($item) => $item->toArray(), $this->domains), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'organization_id' => $this->organizationId, + 'options' => $this->options?->toArray(), + ]; } } diff --git a/lib/Resource/ConnectionActivated.php b/lib/Resource/ConnectionActivated.php new file mode 100644 index 00000000..1dca3d56 --- /dev/null +++ b/lib/Resource/ConnectionActivated.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/ConnectionActivatedContext.php b/lib/Resource/ConnectionActivatedContext.php new file mode 100644 index 00000000..b9ea9cb2 --- /dev/null +++ b/lib/Resource/ConnectionActivatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?ConnectionActivatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? ConnectionActivatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/ConnectionActivatedContextActor.php b/lib/Resource/ConnectionActivatedContextActor.php new file mode 100644 index 00000000..a7f5ba0b --- /dev/null +++ b/lib/Resource/ConnectionActivatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/ConnectionActivatedContextGoogleAnalyticsSession.php b/lib/Resource/ConnectionActivatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..bfdf5b19 --- /dev/null +++ b/lib/Resource/ConnectionActivatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/ConnectionActivatedData.php b/lib/Resource/ConnectionActivatedData.php new file mode 100644 index 00000000..cc3253e8 --- /dev/null +++ b/lib/Resource/ConnectionActivatedData.php @@ -0,0 +1,76 @@ + + */ + public array $domains, + /** The ID of the organization the connection belongs to. */ + public ?string $organizationId = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + state: ConnectionDeletedDataState::from($data['state']), + name: $data['name'], + connectionType: ConnectionDeletedDataConnectionType::from($data['connection_type']), + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + externalKey: $data['external_key'], + status: ConnectionStatus::from($data['status']), + domains: array_map(fn ($item) => ConnectionActivatedDataDomain::fromArray($item), $data['domains']), + organizationId: $data['organization_id'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'state' => $this->state->value, + 'name' => $this->name, + 'connection_type' => $this->connectionType->value, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'external_key' => $this->externalKey, + 'status' => $this->status->value, + 'domains' => array_map(fn ($item) => $item->toArray(), $this->domains), + 'organization_id' => $this->organizationId, + ]; + } +} diff --git a/lib/Resource/ConnectionActivatedDataDomain.php b/lib/Resource/ConnectionActivatedDataDomain.php new file mode 100644 index 00000000..a754bb78 --- /dev/null +++ b/lib/Resource/ConnectionActivatedDataDomain.php @@ -0,0 +1,40 @@ + $this->object, + 'id' => $this->id, + 'domain' => $this->domain, + ]; + } +} diff --git a/lib/Resource/ConnectionDeactivated.php b/lib/Resource/ConnectionDeactivated.php new file mode 100644 index 00000000..3717d46d --- /dev/null +++ b/lib/Resource/ConnectionDeactivated.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/ConnectionDeactivatedContext.php b/lib/Resource/ConnectionDeactivatedContext.php new file mode 100644 index 00000000..fe62b53e --- /dev/null +++ b/lib/Resource/ConnectionDeactivatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?ConnectionDeactivatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? ConnectionDeactivatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/ConnectionDeactivatedContextActor.php b/lib/Resource/ConnectionDeactivatedContextActor.php new file mode 100644 index 00000000..2de44481 --- /dev/null +++ b/lib/Resource/ConnectionDeactivatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/ConnectionDeactivatedContextGoogleAnalyticsSession.php b/lib/Resource/ConnectionDeactivatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..41d1407a --- /dev/null +++ b/lib/Resource/ConnectionDeactivatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/ConnectionDeactivatedData.php b/lib/Resource/ConnectionDeactivatedData.php new file mode 100644 index 00000000..46fca3fd --- /dev/null +++ b/lib/Resource/ConnectionDeactivatedData.php @@ -0,0 +1,76 @@ + + */ + public array $domains, + /** The ID of the organization the connection belongs to. */ + public ?string $organizationId = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + state: ConnectionDeletedDataState::from($data['state']), + name: $data['name'], + connectionType: ConnectionDeletedDataConnectionType::from($data['connection_type']), + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + externalKey: $data['external_key'], + status: ConnectionStatus::from($data['status']), + domains: array_map(fn ($item) => ConnectionDeactivatedDataDomain::fromArray($item), $data['domains']), + organizationId: $data['organization_id'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'state' => $this->state->value, + 'name' => $this->name, + 'connection_type' => $this->connectionType->value, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'external_key' => $this->externalKey, + 'status' => $this->status->value, + 'domains' => array_map(fn ($item) => $item->toArray(), $this->domains), + 'organization_id' => $this->organizationId, + ]; + } +} diff --git a/lib/Resource/ConnectionDeactivatedDataDomain.php b/lib/Resource/ConnectionDeactivatedDataDomain.php new file mode 100644 index 00000000..eeade6b6 --- /dev/null +++ b/lib/Resource/ConnectionDeactivatedDataDomain.php @@ -0,0 +1,40 @@ + $this->object, + 'id' => $this->id, + 'domain' => $this->domain, + ]; + } +} diff --git a/lib/Resource/ConnectionDeleted.php b/lib/Resource/ConnectionDeleted.php new file mode 100644 index 00000000..c71278a0 --- /dev/null +++ b/lib/Resource/ConnectionDeleted.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/ConnectionDeletedContext.php b/lib/Resource/ConnectionDeletedContext.php new file mode 100644 index 00000000..531da61c --- /dev/null +++ b/lib/Resource/ConnectionDeletedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?ConnectionDeletedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? ConnectionDeletedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/ConnectionDeletedContextActor.php b/lib/Resource/ConnectionDeletedContextActor.php new file mode 100644 index 00000000..fe53c6ed --- /dev/null +++ b/lib/Resource/ConnectionDeletedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/ConnectionDeletedContextGoogleAnalyticsSession.php b/lib/Resource/ConnectionDeletedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..6afe2092 --- /dev/null +++ b/lib/Resource/ConnectionDeletedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/ConnectionDeletedData.php b/lib/Resource/ConnectionDeletedData.php new file mode 100644 index 00000000..faa80438 --- /dev/null +++ b/lib/Resource/ConnectionDeletedData.php @@ -0,0 +1,61 @@ + $this->object, + 'id' => $this->id, + 'state' => $this->state->value, + 'name' => $this->name, + 'connection_type' => $this->connectionType->value, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'organization_id' => $this->organizationId, + ]; + } +} diff --git a/lib/Resource/ConnectionDeletedDataConnectionType.php b/lib/Resource/ConnectionDeletedDataConnectionType.php new file mode 100644 index 00000000..fe8afac0 --- /dev/null +++ b/lib/Resource/ConnectionDeletedDataConnectionType.php @@ -0,0 +1,61 @@ + $this->id, + 'object' => $this->object, + 'domain' => $this->domain, + ]; + } +} diff --git a/lib/Resource/ConnectionOption.php b/lib/Resource/ConnectionOption.php new file mode 100644 index 00000000..39e7a2d8 --- /dev/null +++ b/lib/Resource/ConnectionOption.php @@ -0,0 +1,33 @@ + $this->signingCert, + ]; + } +} diff --git a/lib/Resource/ConnectionSAMLCertificateRenewalRequired.php b/lib/Resource/ConnectionSAMLCertificateRenewalRequired.php new file mode 100644 index 00000000..ad55999a --- /dev/null +++ b/lib/Resource/ConnectionSAMLCertificateRenewalRequired.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/ConnectionSAMLCertificateRenewalRequiredContext.php b/lib/Resource/ConnectionSAMLCertificateRenewalRequiredContext.php new file mode 100644 index 00000000..c907f990 --- /dev/null +++ b/lib/Resource/ConnectionSAMLCertificateRenewalRequiredContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?ConnectionSAMLCertificateRenewalRequiredContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? ConnectionSAMLCertificateRenewalRequiredContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/ConnectionSAMLCertificateRenewalRequiredContextActor.php b/lib/Resource/ConnectionSAMLCertificateRenewalRequiredContextActor.php new file mode 100644 index 00000000..93424b72 --- /dev/null +++ b/lib/Resource/ConnectionSAMLCertificateRenewalRequiredContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/ConnectionSAMLCertificateRenewalRequiredContextGoogleAnalyticsSession.php b/lib/Resource/ConnectionSAMLCertificateRenewalRequiredContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..39572e7a --- /dev/null +++ b/lib/Resource/ConnectionSAMLCertificateRenewalRequiredContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/ConnectionSAMLCertificateRenewalRequiredData.php b/lib/Resource/ConnectionSAMLCertificateRenewalRequiredData.php new file mode 100644 index 00000000..0ed371bc --- /dev/null +++ b/lib/Resource/ConnectionSAMLCertificateRenewalRequiredData.php @@ -0,0 +1,41 @@ + $this->connection->toArray(), + 'certificate' => $this->certificate->toArray(), + 'days_until_expiry' => $this->daysUntilExpiry, + ]; + } +} diff --git a/lib/Resource/ConnectionSAMLCertificateRenewalRequiredDataCertificate.php b/lib/Resource/ConnectionSAMLCertificateRenewalRequiredDataCertificate.php new file mode 100644 index 00000000..dfc86fa1 --- /dev/null +++ b/lib/Resource/ConnectionSAMLCertificateRenewalRequiredDataCertificate.php @@ -0,0 +1,41 @@ + $this->certificateType->value, + 'expiry_date' => $this->expiryDate->format(\DateTimeInterface::RFC3339_EXTENDED), + 'is_expired' => $this->isExpired, + ]; + } +} diff --git a/lib/Resource/ConnectionSAMLCertificateRenewalRequiredDataConnection.php b/lib/Resource/ConnectionSAMLCertificateRenewalRequiredDataConnection.php new file mode 100644 index 00000000..f78ece0e --- /dev/null +++ b/lib/Resource/ConnectionSAMLCertificateRenewalRequiredDataConnection.php @@ -0,0 +1,37 @@ + $this->id, + 'organization_id' => $this->organizationId, + ]; + } +} diff --git a/lib/Resource/ConnectionSAMLCertificateRenewed.php b/lib/Resource/ConnectionSAMLCertificateRenewed.php new file mode 100644 index 00000000..38bd0456 --- /dev/null +++ b/lib/Resource/ConnectionSAMLCertificateRenewed.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/ConnectionSAMLCertificateRenewedContext.php b/lib/Resource/ConnectionSAMLCertificateRenewedContext.php new file mode 100644 index 00000000..cb633b2f --- /dev/null +++ b/lib/Resource/ConnectionSAMLCertificateRenewedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?ConnectionSAMLCertificateRenewedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? ConnectionSAMLCertificateRenewedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/ConnectionSAMLCertificateRenewedContextActor.php b/lib/Resource/ConnectionSAMLCertificateRenewedContextActor.php new file mode 100644 index 00000000..cc7854ba --- /dev/null +++ b/lib/Resource/ConnectionSAMLCertificateRenewedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/ConnectionSAMLCertificateRenewedContextGoogleAnalyticsSession.php b/lib/Resource/ConnectionSAMLCertificateRenewedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..e802c6c3 --- /dev/null +++ b/lib/Resource/ConnectionSAMLCertificateRenewedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/ConnectionSAMLCertificateRenewedData.php b/lib/Resource/ConnectionSAMLCertificateRenewedData.php new file mode 100644 index 00000000..cae6888d --- /dev/null +++ b/lib/Resource/ConnectionSAMLCertificateRenewedData.php @@ -0,0 +1,41 @@ + $this->connection->toArray(), + 'certificate' => $this->certificate->toArray(), + 'renewed_at' => $this->renewedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/ConnectionSAMLCertificateRenewedDataCertificate.php b/lib/Resource/ConnectionSAMLCertificateRenewedDataCertificate.php new file mode 100644 index 00000000..424ad65d --- /dev/null +++ b/lib/Resource/ConnectionSAMLCertificateRenewedDataCertificate.php @@ -0,0 +1,37 @@ + $this->certificateType->value, + 'expiry_date' => $this->expiryDate->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/ConnectionSAMLCertificateRenewedDataCertificateCertificateType.php b/lib/Resource/ConnectionSAMLCertificateRenewedDataCertificateCertificateType.php new file mode 100644 index 00000000..3b3a5ab8 --- /dev/null +++ b/lib/Resource/ConnectionSAMLCertificateRenewedDataCertificateCertificateType.php @@ -0,0 +1,14 @@ + $this->id, + 'organization_id' => $this->organizationId, + ]; + } +} diff --git a/lib/Resource/ConnectionState.php b/lib/Resource/ConnectionState.php new file mode 100644 index 00000000..83f6b32e --- /dev/null +++ b/lib/Resource/ConnectionState.php @@ -0,0 +1,17 @@ + $this->slug, + 'name' => $this->name, + 'description' => $this->description, + 'resource_type_slug' => $this->resourceTypeSlug, + ]; + } +} diff --git a/lib/Resource/CreateAuthorizationResource.php b/lib/Resource/CreateAuthorizationResource.php new file mode 100644 index 00000000..1a27a19b --- /dev/null +++ b/lib/Resource/CreateAuthorizationResource.php @@ -0,0 +1,60 @@ + $this->externalId, + 'name' => $this->name, + 'resource_type_slug' => $this->resourceTypeSlug, + 'organization_id' => $this->organizationId, + 'description' => $this->description, + 'parent_resource_id' => $this->parentResourceId, + 'parent_resource_external_id' => $this->parentResourceExternalId, + 'parent_resource_type_slug' => $this->parentResourceTypeSlug, + ]; + } +} diff --git a/lib/Resource/CreateCORSOrigin.php b/lib/Resource/CreateCORSOrigin.php new file mode 100644 index 00000000..30877aeb --- /dev/null +++ b/lib/Resource/CreateCORSOrigin.php @@ -0,0 +1,32 @@ + $this->origin, + ]; + } +} diff --git a/lib/Resource/CreateM2MApplication.php b/lib/Resource/CreateM2MApplication.php new file mode 100644 index 00000000..a0171a12 --- /dev/null +++ b/lib/Resource/CreateM2MApplication.php @@ -0,0 +1,51 @@ +|null + */ + public ?array $scopes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + name: $data['name'], + applicationType: $data['application_type'], + organizationId: $data['organization_id'], + description: $data['description'] ?? null, + scopes: $data['scopes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'name' => $this->name, + 'application_type' => $this->applicationType, + 'organization_id' => $this->organizationId, + 'description' => $this->description, + 'scopes' => $this->scopes, + ]; + } +} diff --git a/lib/Resource/CreateMagicCodeAndReturn.php b/lib/Resource/CreateMagicCodeAndReturn.php new file mode 100644 index 00000000..8272306b --- /dev/null +++ b/lib/Resource/CreateMagicCodeAndReturn.php @@ -0,0 +1,36 @@ + $this->email, + 'invitation_token' => $this->invitationToken, + ]; + } +} diff --git a/lib/Resource/CreateOAuthApplication.php b/lib/Resource/CreateOAuthApplication.php new file mode 100644 index 00000000..b4e9b3a3 --- /dev/null +++ b/lib/Resource/CreateOAuthApplication.php @@ -0,0 +1,66 @@ +|null + */ + public ?array $scopes = null, + /** + * Redirect URIs for the application. + * @var array<\WorkOS\Resource\RedirectUriInput>|null + */ + public ?array $redirectUris = null, + /** Whether the application uses PKCE (Proof Key for Code Exchange). */ + public ?bool $usesPkce = null, + /** The organization ID this application belongs to. Required when is_first_party is false. */ + public ?string $organizationId = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + name: $data['name'], + applicationType: $data['application_type'], + isFirstParty: $data['is_first_party'], + description: $data['description'] ?? null, + scopes: $data['scopes'] ?? null, + redirectUris: isset($data['redirect_uris']) ? array_map(fn ($item) => RedirectUriInput::fromArray($item), $data['redirect_uris']) : null, + usesPkce: $data['uses_pkce'] ?? null, + organizationId: $data['organization_id'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'name' => $this->name, + 'application_type' => $this->applicationType, + 'is_first_party' => $this->isFirstParty, + 'description' => $this->description, + 'scopes' => $this->scopes, + 'redirect_uris' => $this->redirectUris !== null ? array_map(fn ($item) => $item->toArray(), $this->redirectUris) : null, + 'uses_pkce' => $this->usesPkce, + 'organization_id' => $this->organizationId, + ]; + } +} diff --git a/lib/Resource/CreateOrganizationApiKey.php b/lib/Resource/CreateOrganizationApiKey.php new file mode 100644 index 00000000..0ef5b152 --- /dev/null +++ b/lib/Resource/CreateOrganizationApiKey.php @@ -0,0 +1,39 @@ +|null + */ + public ?array $permissions = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + name: $data['name'], + permissions: $data['permissions'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'name' => $this->name, + 'permissions' => $this->permissions, + ]; + } +} diff --git a/lib/Resource/CreateOrganizationDomain.php b/lib/Resource/CreateOrganizationDomain.php new file mode 100644 index 00000000..294c7537 --- /dev/null +++ b/lib/Resource/CreateOrganizationDomain.php @@ -0,0 +1,36 @@ + $this->domain, + 'organization_id' => $this->organizationId, + ]; + } +} diff --git a/lib/Resource/CreateOrganizationRole.php b/lib/Resource/CreateOrganizationRole.php new file mode 100644 index 00000000..2fb5768a --- /dev/null +++ b/lib/Resource/CreateOrganizationRole.php @@ -0,0 +1,44 @@ + $this->name, + 'slug' => $this->slug, + 'description' => $this->description, + 'resource_type_slug' => $this->resourceTypeSlug, + ]; + } +} diff --git a/lib/Resource/CreatePasswordReset.php b/lib/Resource/CreatePasswordReset.php new file mode 100644 index 00000000..6c35df02 --- /dev/null +++ b/lib/Resource/CreatePasswordReset.php @@ -0,0 +1,36 @@ + $this->token, + 'new_password' => $this->newPassword, + ]; + } +} diff --git a/lib/Resource/CreatePasswordResetToken.php b/lib/Resource/CreatePasswordResetToken.php new file mode 100644 index 00000000..0995d756 --- /dev/null +++ b/lib/Resource/CreatePasswordResetToken.php @@ -0,0 +1,32 @@ + $this->email, + ]; + } +} diff --git a/lib/Resource/CreateRedirectUri.php b/lib/Resource/CreateRedirectUri.php new file mode 100644 index 00000000..33fdf694 --- /dev/null +++ b/lib/Resource/CreateRedirectUri.php @@ -0,0 +1,32 @@ + $this->uri, + ]; + } +} diff --git a/lib/Resource/CreateRole.php b/lib/Resource/CreateRole.php new file mode 100644 index 00000000..7356538b --- /dev/null +++ b/lib/Resource/CreateRole.php @@ -0,0 +1,44 @@ + $this->slug, + 'name' => $this->name, + 'description' => $this->description, + 'resource_type_slug' => $this->resourceTypeSlug, + ]; + } +} diff --git a/lib/Resource/CreateUser.php b/lib/Resource/CreateUser.php new file mode 100644 index 00000000..8a439f9c --- /dev/null +++ b/lib/Resource/CreateUser.php @@ -0,0 +1,67 @@ +|null + */ + public ?array $metadata = null, + /** The external ID of the user. */ + public ?string $externalId = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + email: $data['email'], + password: $data['password'] ?? null, + passwordHash: $data['password_hash'] ?? null, + passwordHashType: isset($data['password_hash_type']) ? CreateUserPasswordHashType::from($data['password_hash_type']) : null, + firstName: $data['first_name'] ?? null, + lastName: $data['last_name'] ?? null, + emailVerified: $data['email_verified'] ?? null, + metadata: $data['metadata'] ?? null, + externalId: $data['external_id'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'email' => $this->email, + 'password' => $this->password, + 'password_hash' => $this->passwordHash, + 'password_hash_type' => $this->passwordHashType?->value, + 'first_name' => $this->firstName, + 'last_name' => $this->lastName, + 'email_verified' => $this->emailVerified, + 'metadata' => $this->metadata, + 'external_id' => $this->externalId, + ]; + } +} diff --git a/lib/Resource/CreateUserInviteOptions.php b/lib/Resource/CreateUserInviteOptions.php new file mode 100644 index 00000000..93dfff6a --- /dev/null +++ b/lib/Resource/CreateUserInviteOptions.php @@ -0,0 +1,52 @@ + $this->email, + 'organization_id' => $this->organizationId, + 'role_slug' => $this->roleSlug, + 'expires_in_days' => $this->expiresInDays, + 'inviter_user_id' => $this->inviterUserId, + 'locale' => $this->locale?->value, + ]; + } +} diff --git a/lib/Resource/CreateUserInviteOptionsLocale.php b/lib/Resource/CreateUserInviteOptionsLocale.php new file mode 100644 index 00000000..f3f12bc7 --- /dev/null +++ b/lib/Resource/CreateUserInviteOptionsLocale.php @@ -0,0 +1,101 @@ +|null + */ + public ?array $roleSlugs = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + userId: $data['user_id'], + organizationId: $data['organization_id'], + roleSlug: $data['role_slug'] ?? null, + roleSlugs: $data['role_slugs'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'user_id' => $this->userId, + 'organization_id' => $this->organizationId, + 'role_slug' => $this->roleSlug, + 'role_slugs' => $this->roleSlugs, + ]; + } +} diff --git a/lib/Resource/CreateUserPasswordHashType.php b/lib/Resource/CreateUserPasswordHashType.php new file mode 100644 index 00000000..a3300dc1 --- /dev/null +++ b/lib/Resource/CreateUserPasswordHashType.php @@ -0,0 +1,17 @@ + + */ + public array $events, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + endpointUrl: $data['endpoint_url'], + events: array_map(fn ($item) => CreateWebhookEndpointEvents::from($item), $data['events']), + ); + } + + public function toArray(): array + { + return [ + 'endpoint_url' => $this->endpointUrl, + 'events' => array_map(fn ($item) => $item->value, $this->events), + ]; + } +} diff --git a/lib/Resource/CreateWebhookEndpointEvents.php b/lib/Resource/CreateWebhookEndpointEvents.php new file mode 100644 index 00000000..c4f442ea --- /dev/null +++ b/lib/Resource/CreateWebhookEndpointEvents.php @@ -0,0 +1,80 @@ + $this->url, + ]; + } +} diff --git a/lib/Resource/DataIntegrationsGetDataIntegrationAuthorizeUrlRequest.php b/lib/Resource/DataIntegrationsGetDataIntegrationAuthorizeUrlRequest.php new file mode 100644 index 00000000..37610ca5 --- /dev/null +++ b/lib/Resource/DataIntegrationsGetDataIntegrationAuthorizeUrlRequest.php @@ -0,0 +1,40 @@ + $this->userId, + 'organization_id' => $this->organizationId, + 'return_to' => $this->returnTo, + ]; + } +} diff --git a/lib/Resource/DataIntegrationsGetUserTokenRequest.php b/lib/Resource/DataIntegrationsGetUserTokenRequest.php new file mode 100644 index 00000000..97e2bb2a --- /dev/null +++ b/lib/Resource/DataIntegrationsGetUserTokenRequest.php @@ -0,0 +1,36 @@ + $this->userId, + 'organization_id' => $this->organizationId, + ]; + } +} diff --git a/lib/Resource/DataIntegrationsListResponse.php b/lib/Resource/DataIntegrationsListResponse.php new file mode 100644 index 00000000..3f92a111 --- /dev/null +++ b/lib/Resource/DataIntegrationsListResponse.php @@ -0,0 +1,39 @@ + + */ + public array $data, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + data: array_map(fn ($item) => DataIntegrationsListResponseData::fromArray($item), $data['data']), + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'data' => array_map(fn ($item) => $item->toArray(), $this->data), + ]; + } +} diff --git a/lib/Resource/DataIntegrationsListResponseData.php b/lib/Resource/DataIntegrationsListResponseData.php new file mode 100644 index 00000000..0ce54f8c --- /dev/null +++ b/lib/Resource/DataIntegrationsListResponseData.php @@ -0,0 +1,79 @@ +|null + */ + public ?array $scopes, + /** Whether the provider is owned by a user or organization. */ + public DataIntegrationsListResponseDataOwnership $ownership, + /** The timestamp when the provider was created. */ + public string $createdAt, + /** The timestamp when the provider was last updated. */ + public string $updatedAt, + /** The user's [connected account](https://workos.com/docs/reference/pipes/connected-account) for this provider, or `null` if the user has not connected. */ + public ?DataIntegrationsListResponseDataConnectedAccount $connectedAccount, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + name: $data['name'], + description: $data['description'] ?? null, + slug: $data['slug'], + integrationType: $data['integration_type'], + credentialsType: $data['credentials_type'], + scopes: $data['scopes'] ?? null, + ownership: DataIntegrationsListResponseDataOwnership::from($data['ownership']), + createdAt: $data['created_at'], + updatedAt: $data['updated_at'], + connectedAccount: isset($data['connected_account']) ? DataIntegrationsListResponseDataConnectedAccount::fromArray($data['connected_account']) : null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'name' => $this->name, + 'description' => $this->description, + 'slug' => $this->slug, + 'integration_type' => $this->integrationType, + 'credentials_type' => $this->credentialsType, + 'scopes' => $this->scopes, + 'ownership' => $this->ownership->value, + 'created_at' => $this->createdAt, + 'updated_at' => $this->updatedAt, + 'connected_account' => $this->connectedAccount?->toArray(), + ]; + } +} diff --git a/lib/Resource/DataIntegrationsListResponseDataConnectedAccount.php b/lib/Resource/DataIntegrationsListResponseDataConnectedAccount.php new file mode 100644 index 00000000..fd8946c9 --- /dev/null +++ b/lib/Resource/DataIntegrationsListResponseDataConnectedAccount.php @@ -0,0 +1,75 @@ + + */ + public array $scopes, + /** + * The state of the connected account: + * - `connected`: The connection is active and tokens are valid. + * - `needs_reauthorization`: The user needs to reauthorize the connection, typically because required scopes have changed. + * - `disconnected`: The connection has been disconnected. + */ + public ConnectedAccountState $state, + /** The timestamp when the connection was created. */ + public string $createdAt, + /** The timestamp when the connection was last updated. */ + public string $updatedAt, + /** + * Use `user_id` instead. + * @deprecated + */ + public ?string $userlandUserId, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + userId: $data['user_id'] ?? null, + organizationId: $data['organization_id'] ?? null, + scopes: $data['scopes'], + state: ConnectedAccountState::from($data['state']), + createdAt: $data['created_at'], + updatedAt: $data['updated_at'], + userlandUserId: $data['userlandUserId'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'user_id' => $this->userId, + 'organization_id' => $this->organizationId, + 'scopes' => $this->scopes, + 'state' => $this->state->value, + 'created_at' => $this->createdAt, + 'updated_at' => $this->updatedAt, + 'userlandUserId' => $this->userlandUserId, + ]; + } +} diff --git a/lib/Resource/DataIntegrationsListResponseDataConnectedAccountState.php b/lib/Resource/DataIntegrationsListResponseDataConnectedAccountState.php new file mode 100644 index 00000000..ccfdc223 --- /dev/null +++ b/lib/Resource/DataIntegrationsListResponseDataConnectedAccountState.php @@ -0,0 +1,14 @@ + $this->deviceCode, + 'user_code' => $this->userCode, + 'verification_uri' => $this->verificationUri, + 'expires_in' => $this->expiresIn, + 'verification_uri_complete' => $this->verificationUriComplete, + 'interval' => $this->interval, + ]; + } +} diff --git a/lib/Resource/DeviceCodeSessionAuthenticateRequest.php b/lib/Resource/DeviceCodeSessionAuthenticateRequest.php new file mode 100644 index 00000000..f17a519b --- /dev/null +++ b/lib/Resource/DeviceCodeSessionAuthenticateRequest.php @@ -0,0 +1,51 @@ + $this->clientId, + 'grant_type' => $this->grantType, + 'device_code' => $this->deviceCode, + 'ip_address' => $this->ipAddress, + 'device_id' => $this->deviceId, + 'user_agent' => $this->userAgent, + ]; + } +} diff --git a/lib/Resource/DirectoriesOrder.php b/lib/Resource/DirectoriesOrder.php new file mode 100644 index 00000000..0894e5fc --- /dev/null +++ b/lib/Resource/DirectoriesOrder.php @@ -0,0 +1,14 @@ + "id", - "external_key" => "externalKey", - "organization_id" => "organizationId", - "state" => "state", - "type" => "type", - "name" => "name", - "domain" => "domain" - ]; + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'organization_id' => $this->organizationId, + 'external_key' => $this->externalKey, + 'type' => $this->type->value, + 'state' => $this->state->value, + 'name' => $this->name, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'domain' => $this->domain, + 'metadata' => $this->metadata?->toArray(), + ]; + } } diff --git a/lib/Resource/DirectoryGroup.php b/lib/Resource/DirectoryGroup.php index 25dd3a36..718e1948 100644 --- a/lib/Resource/DirectoryGroup.php +++ b/lib/Resource/DirectoryGroup.php @@ -1,25 +1,67 @@ |null + */ + public ?array $rawAttributes = null, + ) { + } - public const RESOURCE_ATTRIBUTES = [ - "id", - "name", - "directoryId", - "organizationId" - ]; + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + idpId: $data['idp_id'], + directoryId: $data['directory_id'], + organizationId: $data['organization_id'], + name: $data['name'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + rawAttributes: $data['raw_attributes'] ?? null, + ); + } - public const RESPONSE_TO_RESOURCE_KEY = [ - "id" => "id", - "name" => "name", - "directory_id" => "directoryId", - "organization_id" => "organizationId" - ]; + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'idp_id' => $this->idpId, + 'directory_id' => $this->directoryId, + 'organization_id' => $this->organizationId, + 'name' => $this->name, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'raw_attributes' => $this->rawAttributes, + ]; + } } diff --git a/lib/Resource/DirectoryGroupsOrder.php b/lib/Resource/DirectoryGroupsOrder.php new file mode 100644 index 00000000..c6d2b23c --- /dev/null +++ b/lib/Resource/DirectoryGroupsOrder.php @@ -0,0 +1,14 @@ + $this->users->toArray(), + 'groups' => $this->groups, + ]; + } +} diff --git a/lib/Resource/DirectoryMetadataUser.php b/lib/Resource/DirectoryMetadataUser.php new file mode 100644 index 00000000..ad99eb78 --- /dev/null +++ b/lib/Resource/DirectoryMetadataUser.php @@ -0,0 +1,37 @@ + $this->active, + 'inactive' => $this->inactive, + ]; + } +} diff --git a/lib/Resource/DirectoryState.php b/lib/Resource/DirectoryState.php new file mode 100644 index 00000000..40ae98d3 --- /dev/null +++ b/lib/Resource/DirectoryState.php @@ -0,0 +1,16 @@ +|null $roles - */ -class DirectoryUser extends BaseWorkOSResource +readonly class DirectoryUser implements \JsonSerializable { - public const RESOURCE_TYPE = "directory_usr"; + use JsonSerializableTrait; - public const RESOURCE_ATTRIBUTES = [ - "id", - "rawAttributes", - "customAttributes", - "firstName", - "email", + public function __construct( + /** Distinguishes the Directory User object. */ + public string $object, + /** Unique identifier for the Directory User. */ + public string $id, + /** The identifier of the Directory the Directory User belongs to. */ + public string $directoryId, + /** The identifier for the Organization in which the Directory resides. */ + public string $organizationId, + /** Unique identifier for the user, assigned by the Directory Provider. Different Directory Providers use different ID formats. */ + public string $idpId, + /** The email address of the user. */ + public ?string $email, + /** The state of the user. */ + public DirectoryUserState $state, /** - * @deprecated 4.22.0 Will be removed in a future major version. - * Enable the `emails` custom attribute in dashboard and pull from customAttributes instead. - * See https://workos.com/docs/directory-sync/attributes/custom-attributes/auto-mapped-attributes for details. + * The raw attributes received from the directory provider. + * @var array + * @deprecated */ - "emails", + public array $rawAttributes, /** - * @deprecated 4.22.0 Will be removed in a future major version. - * Enable the `username` custom attribute in dashboard and pull from customAttributes instead. - * See https://workos.com/docs/directory-sync/attributes/custom-attributes/auto-mapped-attributes for details. + * An object containing the custom attribute mapping for the Directory Provider. + * @var array */ - "username", - "lastName", + public array $customAttributes, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + /** The first name of the user. */ + public ?string $firstName = null, + /** The last name of the user. */ + public ?string $lastName = null, /** - * @deprecated 4.22.0 Will be removed in a future major version. - * Enable the `job_title` custom attribute in dashboard and pull from customAttributes instead. - * See https://workos.com/docs/directory-sync/attributes/custom-attributes/auto-mapped-attributes for details. + * A list of email addresses for the user. + * @var array<\WorkOS\Resource\DirectoryUserEmail>|null + * @deprecated */ - "jobTitle", - "state", - "idpId", - "role", - "roles", - "groups", - "directoryId", - "organizationId" - ]; - - public const RESPONSE_TO_RESOURCE_KEY = [ - "id" => "id", - "raw_attributes" => "rawAttributes", - "custom_attributes" => "customAttributes", - "first_name" => "firstName", - "email" => "email", - "emails" => "emails", - "username" => "username", - "last_name" => "lastName", - "job_title" => "jobTitle", - "state" => "state", - "idp_id" => "idpId", - "role" => "role", - "roles" => "roles", - "groups" => "groups", - "directory_id" => "directoryId", - "organization_id" => "organizationId" - ]; + public ?array $emails = null, + /** + * The job title of the user. + * @deprecated + */ + public ?string $jobTitle = null, + /** + * The username of the user. + * @deprecated + */ + public ?string $username = null, + public ?SlimRole $role = null, + /** + * All roles assigned to the user. + * @var array<\WorkOS\Resource\SlimRole>|null + */ + public ?array $roles = null, + ) { + } - public static function constructFromResponse($response) + public static function fromArray(array $data): self { - $instance = parent::constructFromResponse($response); - - if (isset($response["role"])) { - $instance->values["role"] = new RoleResponse($response["role"]["slug"]); - } - - if (isset($response["roles"])) { - $roles = []; - foreach ($response["roles"] as $role) { - $roles[] = new RoleResponse($role["slug"]); - } - $instance->values["roles"] = $roles; - } - - return $instance; + return new self( + object: $data['object'], + id: $data['id'], + directoryId: $data['directory_id'], + organizationId: $data['organization_id'], + idpId: $data['idp_id'], + email: $data['email'] ?? null, + state: DirectoryUserState::from($data['state']), + rawAttributes: $data['raw_attributes'], + customAttributes: $data['custom_attributes'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + firstName: $data['first_name'] ?? null, + lastName: $data['last_name'] ?? null, + emails: isset($data['emails']) ? array_map(fn ($item) => DirectoryUserEmail::fromArray($item), $data['emails']) : null, + jobTitle: $data['job_title'] ?? null, + username: $data['username'] ?? null, + role: isset($data['role']) ? SlimRole::fromArray($data['role']) : null, + roles: isset($data['roles']) ? array_map(fn ($item) => SlimRole::fromArray($item), $data['roles']) : null, + ); } - /** - * @deprecated 4.22.0 Use `email` property instead. - * - * @return string|null The primary email address if found, null otherwise - */ - public function primaryEmail() + public function toArray(): array { - $response = $this; - - if (count($response->raw["emails"]) == 0) { - return; - }; - - foreach ($response->raw["emails"] as $value) { - if ($value["primary"] == true) { - return $value["value"]; - }; - }; + return [ + 'object' => $this->object, + 'id' => $this->id, + 'directory_id' => $this->directoryId, + 'organization_id' => $this->organizationId, + 'idp_id' => $this->idpId, + 'email' => $this->email, + 'state' => $this->state->value, + 'raw_attributes' => $this->rawAttributes, + 'custom_attributes' => $this->customAttributes, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'first_name' => $this->firstName, + 'last_name' => $this->lastName, + 'emails' => $this->emails !== null ? array_map(fn ($item) => $item->toArray(), $this->emails) : null, + 'job_title' => $this->jobTitle, + 'username' => $this->username, + 'role' => $this->role?->toArray(), + 'roles' => $this->roles !== null ? array_map(fn ($item) => $item->toArray(), $this->roles) : null, + ]; } } diff --git a/lib/Resource/DirectoryUserEmail.php b/lib/Resource/DirectoryUserEmail.php new file mode 100644 index 00000000..aa10a1b0 --- /dev/null +++ b/lib/Resource/DirectoryUserEmail.php @@ -0,0 +1,40 @@ + $this->primary, + 'type' => $this->type, + 'value' => $this->value, + ]; + } +} diff --git a/lib/Resource/DirectoryUserState.php b/lib/Resource/DirectoryUserState.php new file mode 100644 index 00000000..11f097e3 --- /dev/null +++ b/lib/Resource/DirectoryUserState.php @@ -0,0 +1,14 @@ + + * @deprecated + */ + public array $rawAttributes, + /** + * An object containing the custom attribute mapping for the Directory Provider. + * @var array + */ + public array $customAttributes, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + /** + * The directory groups the user belongs to. + * @var array<\WorkOS\Resource\DirectoryGroup> + */ + public array $groups, + /** The first name of the user. */ + public ?string $firstName = null, + /** The last name of the user. */ + public ?string $lastName = null, + /** + * A list of email addresses for the user. + * @var array<\WorkOS\Resource\DirectoryUserWithGroupsEmail>|null + * @deprecated + */ + public ?array $emails = null, + /** + * The job title of the user. + * @deprecated + */ + public ?string $jobTitle = null, + /** + * The username of the user. + * @deprecated + */ + public ?string $username = null, + public ?SlimRole $role = null, + /** + * All roles assigned to the user. + * @var array<\WorkOS\Resource\SlimRole>|null + */ + public ?array $roles = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + directoryId: $data['directory_id'], + organizationId: $data['organization_id'], + idpId: $data['idp_id'], + email: $data['email'] ?? null, + state: DirectoryUserState::from($data['state']), + rawAttributes: $data['raw_attributes'], + customAttributes: $data['custom_attributes'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + groups: array_map(fn ($item) => DirectoryGroup::fromArray($item), $data['groups']), + firstName: $data['first_name'] ?? null, + lastName: $data['last_name'] ?? null, + emails: isset($data['emails']) ? array_map(fn ($item) => DirectoryUserWithGroupsEmail::fromArray($item), $data['emails']) : null, + jobTitle: $data['job_title'] ?? null, + username: $data['username'] ?? null, + role: isset($data['role']) ? SlimRole::fromArray($data['role']) : null, + roles: isset($data['roles']) ? array_map(fn ($item) => SlimRole::fromArray($item), $data['roles']) : null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'directory_id' => $this->directoryId, + 'organization_id' => $this->organizationId, + 'idp_id' => $this->idpId, + 'email' => $this->email, + 'state' => $this->state->value, + 'raw_attributes' => $this->rawAttributes, + 'custom_attributes' => $this->customAttributes, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'groups' => array_map(fn ($item) => $item->toArray(), $this->groups), + 'first_name' => $this->firstName, + 'last_name' => $this->lastName, + 'emails' => $this->emails !== null ? array_map(fn ($item) => $item->toArray(), $this->emails) : null, + 'job_title' => $this->jobTitle, + 'username' => $this->username, + 'role' => $this->role?->toArray(), + 'roles' => $this->roles !== null ? array_map(fn ($item) => $item->toArray(), $this->roles) : null, + ]; + } +} diff --git a/lib/Resource/DirectoryUserWithGroupsEmail.php b/lib/Resource/DirectoryUserWithGroupsEmail.php new file mode 100644 index 00000000..7fd73f0a --- /dev/null +++ b/lib/Resource/DirectoryUserWithGroupsEmail.php @@ -0,0 +1,40 @@ + $this->primary, + 'type' => $this->type, + 'value' => $this->value, + ]; + } +} diff --git a/lib/Resource/DirectoryUserWithGroupsState.php b/lib/Resource/DirectoryUserWithGroupsState.php new file mode 100644 index 00000000..73e4f7f9 --- /dev/null +++ b/lib/Resource/DirectoryUserWithGroupsState.php @@ -0,0 +1,14 @@ + "id", - "domain" => "domain" - ]; -} diff --git a/lib/Resource/DsyncActivated.php b/lib/Resource/DsyncActivated.php new file mode 100644 index 00000000..3cf12d0f --- /dev/null +++ b/lib/Resource/DsyncActivated.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/DsyncActivatedContext.php b/lib/Resource/DsyncActivatedContext.php new file mode 100644 index 00000000..ce24a550 --- /dev/null +++ b/lib/Resource/DsyncActivatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?DsyncActivatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? DsyncActivatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/DsyncActivatedContextActor.php b/lib/Resource/DsyncActivatedContextActor.php new file mode 100644 index 00000000..c3151a06 --- /dev/null +++ b/lib/Resource/DsyncActivatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/DsyncActivatedContextGoogleAnalyticsSession.php b/lib/Resource/DsyncActivatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..576431a8 --- /dev/null +++ b/lib/Resource/DsyncActivatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/DsyncActivatedData.php b/lib/Resource/DsyncActivatedData.php new file mode 100644 index 00000000..0bccbed7 --- /dev/null +++ b/lib/Resource/DsyncActivatedData.php @@ -0,0 +1,72 @@ + + */ + public array $domains, + /** The ID of the organization the directory belongs to. */ + public ?string $organizationId = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + type: DsyncDeletedDataType::from($data['type']), + state: DsyncDeletedDataState::from($data['state']), + name: $data['name'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + externalKey: $data['external_key'], + domains: array_map(fn ($item) => DsyncActivatedDataDomain::fromArray($item), $data['domains']), + organizationId: $data['organization_id'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'type' => $this->type->value, + 'state' => $this->state->value, + 'name' => $this->name, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'external_key' => $this->externalKey, + 'domains' => array_map(fn ($item) => $item->toArray(), $this->domains), + 'organization_id' => $this->organizationId, + ]; + } +} diff --git a/lib/Resource/DsyncActivatedDataDomain.php b/lib/Resource/DsyncActivatedDataDomain.php new file mode 100644 index 00000000..d3b915dd --- /dev/null +++ b/lib/Resource/DsyncActivatedDataDomain.php @@ -0,0 +1,40 @@ + $this->object, + 'id' => $this->id, + 'domain' => $this->domain, + ]; + } +} diff --git a/lib/Resource/DsyncDeactivated.php b/lib/Resource/DsyncDeactivated.php new file mode 100644 index 00000000..3fac9e90 --- /dev/null +++ b/lib/Resource/DsyncDeactivated.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/DsyncDeactivatedContext.php b/lib/Resource/DsyncDeactivatedContext.php new file mode 100644 index 00000000..c965ccb0 --- /dev/null +++ b/lib/Resource/DsyncDeactivatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?DsyncDeactivatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? DsyncDeactivatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/DsyncDeactivatedContextActor.php b/lib/Resource/DsyncDeactivatedContextActor.php new file mode 100644 index 00000000..5d098d0a --- /dev/null +++ b/lib/Resource/DsyncDeactivatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/DsyncDeactivatedContextGoogleAnalyticsSession.php b/lib/Resource/DsyncDeactivatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..de94ada4 --- /dev/null +++ b/lib/Resource/DsyncDeactivatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/DsyncDeactivatedData.php b/lib/Resource/DsyncDeactivatedData.php new file mode 100644 index 00000000..3dab0206 --- /dev/null +++ b/lib/Resource/DsyncDeactivatedData.php @@ -0,0 +1,72 @@ + + */ + public array $domains, + /** The ID of the organization the directory belongs to. */ + public ?string $organizationId = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + type: DsyncDeletedDataType::from($data['type']), + state: DsyncDeletedDataState::from($data['state']), + name: $data['name'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + externalKey: $data['external_key'], + domains: array_map(fn ($item) => DsyncDeactivatedDataDomain::fromArray($item), $data['domains']), + organizationId: $data['organization_id'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'type' => $this->type->value, + 'state' => $this->state->value, + 'name' => $this->name, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'external_key' => $this->externalKey, + 'domains' => array_map(fn ($item) => $item->toArray(), $this->domains), + 'organization_id' => $this->organizationId, + ]; + } +} diff --git a/lib/Resource/DsyncDeactivatedDataDomain.php b/lib/Resource/DsyncDeactivatedDataDomain.php new file mode 100644 index 00000000..a736d6f3 --- /dev/null +++ b/lib/Resource/DsyncDeactivatedDataDomain.php @@ -0,0 +1,40 @@ + $this->object, + 'id' => $this->id, + 'domain' => $this->domain, + ]; + } +} diff --git a/lib/Resource/DsyncDeleted.php b/lib/Resource/DsyncDeleted.php new file mode 100644 index 00000000..1fd1edca --- /dev/null +++ b/lib/Resource/DsyncDeleted.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/DsyncDeletedContext.php b/lib/Resource/DsyncDeletedContext.php new file mode 100644 index 00000000..3fb49b76 --- /dev/null +++ b/lib/Resource/DsyncDeletedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?DsyncDeletedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? DsyncDeletedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/DsyncDeletedContextActor.php b/lib/Resource/DsyncDeletedContextActor.php new file mode 100644 index 00000000..1ce99043 --- /dev/null +++ b/lib/Resource/DsyncDeletedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/DsyncDeletedContextGoogleAnalyticsSession.php b/lib/Resource/DsyncDeletedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..e63d45b5 --- /dev/null +++ b/lib/Resource/DsyncDeletedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/DsyncDeletedData.php b/lib/Resource/DsyncDeletedData.php new file mode 100644 index 00000000..7540e522 --- /dev/null +++ b/lib/Resource/DsyncDeletedData.php @@ -0,0 +1,61 @@ + $this->object, + 'id' => $this->id, + 'type' => $this->type->value, + 'state' => $this->state->value, + 'name' => $this->name, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'organization_id' => $this->organizationId, + ]; + } +} diff --git a/lib/Resource/DsyncDeletedDataState.php b/lib/Resource/DsyncDeletedDataState.php new file mode 100644 index 00000000..be189dd0 --- /dev/null +++ b/lib/Resource/DsyncDeletedDataState.php @@ -0,0 +1,16 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/DsyncGroupCreatedContext.php b/lib/Resource/DsyncGroupCreatedContext.php new file mode 100644 index 00000000..85e5ab15 --- /dev/null +++ b/lib/Resource/DsyncGroupCreatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?DsyncGroupCreatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? DsyncGroupCreatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/DsyncGroupCreatedContextActor.php b/lib/Resource/DsyncGroupCreatedContextActor.php new file mode 100644 index 00000000..f0cfa0f6 --- /dev/null +++ b/lib/Resource/DsyncGroupCreatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/DsyncGroupCreatedContextGoogleAnalyticsSession.php b/lib/Resource/DsyncGroupCreatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..e7e2e421 --- /dev/null +++ b/lib/Resource/DsyncGroupCreatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/DsyncGroupCreatedData.php b/lib/Resource/DsyncGroupCreatedData.php new file mode 100644 index 00000000..240afcd0 --- /dev/null +++ b/lib/Resource/DsyncGroupCreatedData.php @@ -0,0 +1,68 @@ +|null + */ + public ?array $rawAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + idpId: $data['idp_id'], + directoryId: $data['directory_id'], + organizationId: $data['organization_id'], + name: $data['name'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + rawAttributes: $data['raw_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'idp_id' => $this->idpId, + 'directory_id' => $this->directoryId, + 'organization_id' => $this->organizationId, + 'name' => $this->name, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'raw_attributes' => $this->rawAttributes, + ]; + } +} diff --git a/lib/Resource/DsyncGroupDeleted.php b/lib/Resource/DsyncGroupDeleted.php new file mode 100644 index 00000000..8644a5ff --- /dev/null +++ b/lib/Resource/DsyncGroupDeleted.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/DsyncGroupDeletedContext.php b/lib/Resource/DsyncGroupDeletedContext.php new file mode 100644 index 00000000..f3225e22 --- /dev/null +++ b/lib/Resource/DsyncGroupDeletedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?DsyncGroupDeletedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? DsyncGroupDeletedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/DsyncGroupDeletedContextActor.php b/lib/Resource/DsyncGroupDeletedContextActor.php new file mode 100644 index 00000000..6ed82e63 --- /dev/null +++ b/lib/Resource/DsyncGroupDeletedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/DsyncGroupDeletedContextGoogleAnalyticsSession.php b/lib/Resource/DsyncGroupDeletedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..cc3dbed4 --- /dev/null +++ b/lib/Resource/DsyncGroupDeletedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/DsyncGroupDeletedData.php b/lib/Resource/DsyncGroupDeletedData.php new file mode 100644 index 00000000..19d45c88 --- /dev/null +++ b/lib/Resource/DsyncGroupDeletedData.php @@ -0,0 +1,68 @@ +|null + */ + public ?array $rawAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + idpId: $data['idp_id'], + directoryId: $data['directory_id'], + organizationId: $data['organization_id'], + name: $data['name'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + rawAttributes: $data['raw_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'idp_id' => $this->idpId, + 'directory_id' => $this->directoryId, + 'organization_id' => $this->organizationId, + 'name' => $this->name, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'raw_attributes' => $this->rawAttributes, + ]; + } +} diff --git a/lib/Resource/DsyncGroupUpdated.php b/lib/Resource/DsyncGroupUpdated.php new file mode 100644 index 00000000..ecd476a0 --- /dev/null +++ b/lib/Resource/DsyncGroupUpdated.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/DsyncGroupUpdatedContext.php b/lib/Resource/DsyncGroupUpdatedContext.php new file mode 100644 index 00000000..a2c42356 --- /dev/null +++ b/lib/Resource/DsyncGroupUpdatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?DsyncGroupUpdatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? DsyncGroupUpdatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/DsyncGroupUpdatedContextActor.php b/lib/Resource/DsyncGroupUpdatedContextActor.php new file mode 100644 index 00000000..f1eac434 --- /dev/null +++ b/lib/Resource/DsyncGroupUpdatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/DsyncGroupUpdatedContextGoogleAnalyticsSession.php b/lib/Resource/DsyncGroupUpdatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..25cf8562 --- /dev/null +++ b/lib/Resource/DsyncGroupUpdatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/DsyncGroupUpdatedData.php b/lib/Resource/DsyncGroupUpdatedData.php new file mode 100644 index 00000000..d588072f --- /dev/null +++ b/lib/Resource/DsyncGroupUpdatedData.php @@ -0,0 +1,72 @@ +|null + */ + public ?array $rawAttributes = null, + /** @var array|null */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + idpId: $data['idp_id'], + directoryId: $data['directory_id'], + organizationId: $data['organization_id'], + name: $data['name'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + rawAttributes: $data['raw_attributes'] ?? null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'idp_id' => $this->idpId, + 'directory_id' => $this->directoryId, + 'organization_id' => $this->organizationId, + 'name' => $this->name, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'raw_attributes' => $this->rawAttributes, + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/DsyncGroupUserAdded.php b/lib/Resource/DsyncGroupUserAdded.php new file mode 100644 index 00000000..04a5e3bc --- /dev/null +++ b/lib/Resource/DsyncGroupUserAdded.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/DsyncGroupUserAddedContext.php b/lib/Resource/DsyncGroupUserAddedContext.php new file mode 100644 index 00000000..6e1887e5 --- /dev/null +++ b/lib/Resource/DsyncGroupUserAddedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?DsyncGroupUserAddedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? DsyncGroupUserAddedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/DsyncGroupUserAddedContextActor.php b/lib/Resource/DsyncGroupUserAddedContextActor.php new file mode 100644 index 00000000..5967519f --- /dev/null +++ b/lib/Resource/DsyncGroupUserAddedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/DsyncGroupUserAddedContextGoogleAnalyticsSession.php b/lib/Resource/DsyncGroupUserAddedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..2965b1be --- /dev/null +++ b/lib/Resource/DsyncGroupUserAddedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/DsyncGroupUserAddedData.php b/lib/Resource/DsyncGroupUserAddedData.php new file mode 100644 index 00000000..c906930e --- /dev/null +++ b/lib/Resource/DsyncGroupUserAddedData.php @@ -0,0 +1,41 @@ + $this->directoryId, + 'user' => $this->user->toArray(), + 'group' => $this->group->toArray(), + ]; + } +} diff --git a/lib/Resource/DsyncGroupUserAddedDataGroup.php b/lib/Resource/DsyncGroupUserAddedDataGroup.php new file mode 100644 index 00000000..32e76435 --- /dev/null +++ b/lib/Resource/DsyncGroupUserAddedDataGroup.php @@ -0,0 +1,68 @@ +|null + */ + public ?array $rawAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + idpId: $data['idp_id'], + directoryId: $data['directory_id'], + organizationId: $data['organization_id'], + name: $data['name'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + rawAttributes: $data['raw_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'idp_id' => $this->idpId, + 'directory_id' => $this->directoryId, + 'organization_id' => $this->organizationId, + 'name' => $this->name, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'raw_attributes' => $this->rawAttributes, + ]; + } +} diff --git a/lib/Resource/DsyncGroupUserAddedDataUser.php b/lib/Resource/DsyncGroupUserAddedDataUser.php new file mode 100644 index 00000000..93ea4824 --- /dev/null +++ b/lib/Resource/DsyncGroupUserAddedDataUser.php @@ -0,0 +1,121 @@ + + * @deprecated + */ + public array $rawAttributes, + /** + * An object containing the custom attribute mapping for the Directory Provider. + * @var array + */ + public array $customAttributes, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + /** The first name of the user. */ + public ?string $firstName = null, + /** The last name of the user. */ + public ?string $lastName = null, + /** + * A list of email addresses for the user. + * @var array<\WorkOS\Resource\DsyncGroupUserAddedDataUserEmail>|null + * @deprecated + */ + public ?array $emails = null, + /** + * The job title of the user. + * @deprecated + */ + public ?string $jobTitle = null, + /** + * The username of the user. + * @deprecated + */ + public ?string $username = null, + /** The primary role assigned to the user. */ + public ?DsyncGroupUserAddedDataUserRole $role = null, + /** + * All roles assigned to the user. + * @var array<\WorkOS\Resource\DsyncGroupUserAddedDataUserRole>|null + */ + public ?array $roles = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + directoryId: $data['directory_id'], + organizationId: $data['organization_id'], + idpId: $data['idp_id'], + email: $data['email'] ?? null, + state: DsyncUserCreatedDataState::from($data['state']), + rawAttributes: $data['raw_attributes'], + customAttributes: $data['custom_attributes'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + firstName: $data['first_name'] ?? null, + lastName: $data['last_name'] ?? null, + emails: $data['emails'] ?? null, + jobTitle: $data['job_title'] ?? null, + username: $data['username'] ?? null, + role: isset($data['role']) ? DsyncGroupUserAddedDataUserRole::fromArray($data['role']) : null, + roles: $data['roles'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'directory_id' => $this->directoryId, + 'organization_id' => $this->organizationId, + 'idp_id' => $this->idpId, + 'email' => $this->email, + 'state' => $this->state->value, + 'raw_attributes' => $this->rawAttributes, + 'custom_attributes' => $this->customAttributes, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'first_name' => $this->firstName, + 'last_name' => $this->lastName, + 'emails' => $this->emails !== null ? array_map(fn ($item) => $item->toArray(), $this->emails) : null, + 'job_title' => $this->jobTitle, + 'username' => $this->username, + 'role' => $this->role?->toArray(), + 'roles' => $this->roles !== null ? array_map(fn ($item) => $item->toArray(), $this->roles) : null, + ]; + } +} diff --git a/lib/Resource/DsyncGroupUserAddedDataUserEmail.php b/lib/Resource/DsyncGroupUserAddedDataUserEmail.php new file mode 100644 index 00000000..0e8a0ff0 --- /dev/null +++ b/lib/Resource/DsyncGroupUserAddedDataUserEmail.php @@ -0,0 +1,40 @@ + $this->primary, + 'type' => $this->type, + 'value' => $this->value, + ]; + } +} diff --git a/lib/Resource/DsyncGroupUserAddedDataUserRole.php b/lib/Resource/DsyncGroupUserAddedDataUserRole.php new file mode 100644 index 00000000..ab06ec9b --- /dev/null +++ b/lib/Resource/DsyncGroupUserAddedDataUserRole.php @@ -0,0 +1,33 @@ + $this->slug, + ]; + } +} diff --git a/lib/Resource/DsyncGroupUserRemoved.php b/lib/Resource/DsyncGroupUserRemoved.php new file mode 100644 index 00000000..005192a2 --- /dev/null +++ b/lib/Resource/DsyncGroupUserRemoved.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/DsyncGroupUserRemovedContext.php b/lib/Resource/DsyncGroupUserRemovedContext.php new file mode 100644 index 00000000..979bab6e --- /dev/null +++ b/lib/Resource/DsyncGroupUserRemovedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?DsyncGroupUserRemovedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? DsyncGroupUserRemovedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/DsyncGroupUserRemovedContextActor.php b/lib/Resource/DsyncGroupUserRemovedContextActor.php new file mode 100644 index 00000000..e5177d68 --- /dev/null +++ b/lib/Resource/DsyncGroupUserRemovedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/DsyncGroupUserRemovedContextGoogleAnalyticsSession.php b/lib/Resource/DsyncGroupUserRemovedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..87345378 --- /dev/null +++ b/lib/Resource/DsyncGroupUserRemovedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/DsyncGroupUserRemovedData.php b/lib/Resource/DsyncGroupUserRemovedData.php new file mode 100644 index 00000000..d408bf2a --- /dev/null +++ b/lib/Resource/DsyncGroupUserRemovedData.php @@ -0,0 +1,41 @@ + $this->directoryId, + 'user' => $this->user->toArray(), + 'group' => $this->group->toArray(), + ]; + } +} diff --git a/lib/Resource/DsyncGroupUserRemovedDataGroup.php b/lib/Resource/DsyncGroupUserRemovedDataGroup.php new file mode 100644 index 00000000..36b25f47 --- /dev/null +++ b/lib/Resource/DsyncGroupUserRemovedDataGroup.php @@ -0,0 +1,68 @@ +|null + */ + public ?array $rawAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + idpId: $data['idp_id'], + directoryId: $data['directory_id'], + organizationId: $data['organization_id'], + name: $data['name'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + rawAttributes: $data['raw_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'idp_id' => $this->idpId, + 'directory_id' => $this->directoryId, + 'organization_id' => $this->organizationId, + 'name' => $this->name, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'raw_attributes' => $this->rawAttributes, + ]; + } +} diff --git a/lib/Resource/DsyncGroupUserRemovedDataUser.php b/lib/Resource/DsyncGroupUserRemovedDataUser.php new file mode 100644 index 00000000..177e52da --- /dev/null +++ b/lib/Resource/DsyncGroupUserRemovedDataUser.php @@ -0,0 +1,121 @@ + + * @deprecated + */ + public array $rawAttributes, + /** + * An object containing the custom attribute mapping for the Directory Provider. + * @var array + */ + public array $customAttributes, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + /** The first name of the user. */ + public ?string $firstName = null, + /** The last name of the user. */ + public ?string $lastName = null, + /** + * A list of email addresses for the user. + * @var array<\WorkOS\Resource\DsyncGroupUserRemovedDataUserEmail>|null + * @deprecated + */ + public ?array $emails = null, + /** + * The job title of the user. + * @deprecated + */ + public ?string $jobTitle = null, + /** + * The username of the user. + * @deprecated + */ + public ?string $username = null, + /** The primary role assigned to the user. */ + public ?DsyncGroupUserRemovedDataUserRole $role = null, + /** + * All roles assigned to the user. + * @var array<\WorkOS\Resource\DsyncGroupUserRemovedDataUserRole>|null + */ + public ?array $roles = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + directoryId: $data['directory_id'], + organizationId: $data['organization_id'], + idpId: $data['idp_id'], + email: $data['email'] ?? null, + state: DsyncUserCreatedDataState::from($data['state']), + rawAttributes: $data['raw_attributes'], + customAttributes: $data['custom_attributes'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + firstName: $data['first_name'] ?? null, + lastName: $data['last_name'] ?? null, + emails: $data['emails'] ?? null, + jobTitle: $data['job_title'] ?? null, + username: $data['username'] ?? null, + role: isset($data['role']) ? DsyncGroupUserRemovedDataUserRole::fromArray($data['role']) : null, + roles: $data['roles'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'directory_id' => $this->directoryId, + 'organization_id' => $this->organizationId, + 'idp_id' => $this->idpId, + 'email' => $this->email, + 'state' => $this->state->value, + 'raw_attributes' => $this->rawAttributes, + 'custom_attributes' => $this->customAttributes, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'first_name' => $this->firstName, + 'last_name' => $this->lastName, + 'emails' => $this->emails !== null ? array_map(fn ($item) => $item->toArray(), $this->emails) : null, + 'job_title' => $this->jobTitle, + 'username' => $this->username, + 'role' => $this->role?->toArray(), + 'roles' => $this->roles !== null ? array_map(fn ($item) => $item->toArray(), $this->roles) : null, + ]; + } +} diff --git a/lib/Resource/DsyncGroupUserRemovedDataUserEmail.php b/lib/Resource/DsyncGroupUserRemovedDataUserEmail.php new file mode 100644 index 00000000..cc0be4d5 --- /dev/null +++ b/lib/Resource/DsyncGroupUserRemovedDataUserEmail.php @@ -0,0 +1,40 @@ + $this->primary, + 'type' => $this->type, + 'value' => $this->value, + ]; + } +} diff --git a/lib/Resource/DsyncGroupUserRemovedDataUserRole.php b/lib/Resource/DsyncGroupUserRemovedDataUserRole.php new file mode 100644 index 00000000..fec8a53e --- /dev/null +++ b/lib/Resource/DsyncGroupUserRemovedDataUserRole.php @@ -0,0 +1,33 @@ + $this->slug, + ]; + } +} diff --git a/lib/Resource/DsyncUserCreated.php b/lib/Resource/DsyncUserCreated.php new file mode 100644 index 00000000..c6b5b282 --- /dev/null +++ b/lib/Resource/DsyncUserCreated.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/DsyncUserCreatedContext.php b/lib/Resource/DsyncUserCreatedContext.php new file mode 100644 index 00000000..f26a8f27 --- /dev/null +++ b/lib/Resource/DsyncUserCreatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?DsyncUserCreatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? DsyncUserCreatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/DsyncUserCreatedContextActor.php b/lib/Resource/DsyncUserCreatedContextActor.php new file mode 100644 index 00000000..c64ec8d6 --- /dev/null +++ b/lib/Resource/DsyncUserCreatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/DsyncUserCreatedContextGoogleAnalyticsSession.php b/lib/Resource/DsyncUserCreatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..83545f4a --- /dev/null +++ b/lib/Resource/DsyncUserCreatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/DsyncUserCreatedData.php b/lib/Resource/DsyncUserCreatedData.php new file mode 100644 index 00000000..05194291 --- /dev/null +++ b/lib/Resource/DsyncUserCreatedData.php @@ -0,0 +1,121 @@ + + * @deprecated + */ + public array $rawAttributes, + /** + * An object containing the custom attribute mapping for the Directory Provider. + * @var array + */ + public array $customAttributes, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + /** The first name of the user. */ + public ?string $firstName = null, + /** The last name of the user. */ + public ?string $lastName = null, + /** + * A list of email addresses for the user. + * @var array<\WorkOS\Resource\DsyncUserCreatedDataEmail>|null + * @deprecated + */ + public ?array $emails = null, + /** + * The job title of the user. + * @deprecated + */ + public ?string $jobTitle = null, + /** + * The username of the user. + * @deprecated + */ + public ?string $username = null, + /** The primary role assigned to the user. */ + public ?DsyncUserCreatedDataRole $role = null, + /** + * All roles assigned to the user. + * @var array<\WorkOS\Resource\DsyncUserCreatedDataRole>|null + */ + public ?array $roles = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + directoryId: $data['directory_id'], + organizationId: $data['organization_id'], + idpId: $data['idp_id'], + email: $data['email'] ?? null, + state: DsyncUserCreatedDataState::from($data['state']), + rawAttributes: $data['raw_attributes'], + customAttributes: $data['custom_attributes'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + firstName: $data['first_name'] ?? null, + lastName: $data['last_name'] ?? null, + emails: $data['emails'] ?? null, + jobTitle: $data['job_title'] ?? null, + username: $data['username'] ?? null, + role: isset($data['role']) ? DsyncUserCreatedDataRole::fromArray($data['role']) : null, + roles: $data['roles'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'directory_id' => $this->directoryId, + 'organization_id' => $this->organizationId, + 'idp_id' => $this->idpId, + 'email' => $this->email, + 'state' => $this->state->value, + 'raw_attributes' => $this->rawAttributes, + 'custom_attributes' => $this->customAttributes, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'first_name' => $this->firstName, + 'last_name' => $this->lastName, + 'emails' => $this->emails !== null ? array_map(fn ($item) => $item->toArray(), $this->emails) : null, + 'job_title' => $this->jobTitle, + 'username' => $this->username, + 'role' => $this->role?->toArray(), + 'roles' => $this->roles !== null ? array_map(fn ($item) => $item->toArray(), $this->roles) : null, + ]; + } +} diff --git a/lib/Resource/DsyncUserCreatedDataEmail.php b/lib/Resource/DsyncUserCreatedDataEmail.php new file mode 100644 index 00000000..f4937c34 --- /dev/null +++ b/lib/Resource/DsyncUserCreatedDataEmail.php @@ -0,0 +1,40 @@ + $this->primary, + 'type' => $this->type, + 'value' => $this->value, + ]; + } +} diff --git a/lib/Resource/DsyncUserCreatedDataRole.php b/lib/Resource/DsyncUserCreatedDataRole.php new file mode 100644 index 00000000..fbdcff04 --- /dev/null +++ b/lib/Resource/DsyncUserCreatedDataRole.php @@ -0,0 +1,33 @@ + $this->slug, + ]; + } +} diff --git a/lib/Resource/DsyncUserCreatedDataState.php b/lib/Resource/DsyncUserCreatedDataState.php new file mode 100644 index 00000000..9351f82c --- /dev/null +++ b/lib/Resource/DsyncUserCreatedDataState.php @@ -0,0 +1,14 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/DsyncUserDeletedContext.php b/lib/Resource/DsyncUserDeletedContext.php new file mode 100644 index 00000000..8637df79 --- /dev/null +++ b/lib/Resource/DsyncUserDeletedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?DsyncUserDeletedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? DsyncUserDeletedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/DsyncUserDeletedContextActor.php b/lib/Resource/DsyncUserDeletedContextActor.php new file mode 100644 index 00000000..b2f5c35b --- /dev/null +++ b/lib/Resource/DsyncUserDeletedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/DsyncUserDeletedContextGoogleAnalyticsSession.php b/lib/Resource/DsyncUserDeletedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..8658d67e --- /dev/null +++ b/lib/Resource/DsyncUserDeletedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/DsyncUserDeletedData.php b/lib/Resource/DsyncUserDeletedData.php new file mode 100644 index 00000000..decfdb90 --- /dev/null +++ b/lib/Resource/DsyncUserDeletedData.php @@ -0,0 +1,121 @@ + + * @deprecated + */ + public array $rawAttributes, + /** + * An object containing the custom attribute mapping for the Directory Provider. + * @var array + */ + public array $customAttributes, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + /** The first name of the user. */ + public ?string $firstName = null, + /** The last name of the user. */ + public ?string $lastName = null, + /** + * A list of email addresses for the user. + * @var array<\WorkOS\Resource\DsyncUserDeletedDataEmail>|null + * @deprecated + */ + public ?array $emails = null, + /** + * The job title of the user. + * @deprecated + */ + public ?string $jobTitle = null, + /** + * The username of the user. + * @deprecated + */ + public ?string $username = null, + /** The primary role assigned to the user. */ + public ?DsyncUserDeletedDataRole $role = null, + /** + * All roles assigned to the user. + * @var array<\WorkOS\Resource\DsyncUserDeletedDataRole>|null + */ + public ?array $roles = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + directoryId: $data['directory_id'], + organizationId: $data['organization_id'], + idpId: $data['idp_id'], + email: $data['email'] ?? null, + state: DsyncUserCreatedDataState::from($data['state']), + rawAttributes: $data['raw_attributes'], + customAttributes: $data['custom_attributes'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + firstName: $data['first_name'] ?? null, + lastName: $data['last_name'] ?? null, + emails: $data['emails'] ?? null, + jobTitle: $data['job_title'] ?? null, + username: $data['username'] ?? null, + role: isset($data['role']) ? DsyncUserDeletedDataRole::fromArray($data['role']) : null, + roles: $data['roles'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'directory_id' => $this->directoryId, + 'organization_id' => $this->organizationId, + 'idp_id' => $this->idpId, + 'email' => $this->email, + 'state' => $this->state->value, + 'raw_attributes' => $this->rawAttributes, + 'custom_attributes' => $this->customAttributes, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'first_name' => $this->firstName, + 'last_name' => $this->lastName, + 'emails' => $this->emails !== null ? array_map(fn ($item) => $item->toArray(), $this->emails) : null, + 'job_title' => $this->jobTitle, + 'username' => $this->username, + 'role' => $this->role?->toArray(), + 'roles' => $this->roles !== null ? array_map(fn ($item) => $item->toArray(), $this->roles) : null, + ]; + } +} diff --git a/lib/Resource/DsyncUserDeletedDataEmail.php b/lib/Resource/DsyncUserDeletedDataEmail.php new file mode 100644 index 00000000..833e1331 --- /dev/null +++ b/lib/Resource/DsyncUserDeletedDataEmail.php @@ -0,0 +1,40 @@ + $this->primary, + 'type' => $this->type, + 'value' => $this->value, + ]; + } +} diff --git a/lib/Resource/DsyncUserDeletedDataRole.php b/lib/Resource/DsyncUserDeletedDataRole.php new file mode 100644 index 00000000..5978ed09 --- /dev/null +++ b/lib/Resource/DsyncUserDeletedDataRole.php @@ -0,0 +1,33 @@ + $this->slug, + ]; + } +} diff --git a/lib/Resource/DsyncUserUpdated.php b/lib/Resource/DsyncUserUpdated.php new file mode 100644 index 00000000..020f6d8f --- /dev/null +++ b/lib/Resource/DsyncUserUpdated.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/DsyncUserUpdatedContext.php b/lib/Resource/DsyncUserUpdatedContext.php new file mode 100644 index 00000000..7c700164 --- /dev/null +++ b/lib/Resource/DsyncUserUpdatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?DsyncUserUpdatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? DsyncUserUpdatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/DsyncUserUpdatedContextActor.php b/lib/Resource/DsyncUserUpdatedContextActor.php new file mode 100644 index 00000000..2ea30d27 --- /dev/null +++ b/lib/Resource/DsyncUserUpdatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/DsyncUserUpdatedContextGoogleAnalyticsSession.php b/lib/Resource/DsyncUserUpdatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..b31f1b6c --- /dev/null +++ b/lib/Resource/DsyncUserUpdatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/DsyncUserUpdatedData.php b/lib/Resource/DsyncUserUpdatedData.php new file mode 100644 index 00000000..488b229d --- /dev/null +++ b/lib/Resource/DsyncUserUpdatedData.php @@ -0,0 +1,124 @@ + + * @deprecated + */ + public array $rawAttributes, + /** + * An object containing the custom attribute mapping for the Directory Provider. + * @var array + */ + public array $customAttributes, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + /** The first name of the user. */ + public ?string $firstName = null, + /** The last name of the user. */ + public ?string $lastName = null, + /** + * A list of email addresses for the user. + * @var array<\WorkOS\Resource\DsyncUserUpdatedDataEmail>|null + * @deprecated + */ + public ?array $emails = null, + /** + * The job title of the user. + * @deprecated + */ + public ?string $jobTitle = null, + /** + * The username of the user. + * @deprecated + */ + public ?string $username = null, + public ?SlimRole $role = null, + /** + * All roles assigned to the user. + * @var array<\WorkOS\Resource\SlimRole>|null + */ + public ?array $roles = null, + /** @var array|null */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + directoryId: $data['directory_id'], + organizationId: $data['organization_id'], + idpId: $data['idp_id'], + email: $data['email'] ?? null, + state: DirectoryUserState::from($data['state']), + rawAttributes: $data['raw_attributes'], + customAttributes: $data['custom_attributes'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + firstName: $data['first_name'] ?? null, + lastName: $data['last_name'] ?? null, + emails: isset($data['emails']) ? array_map(fn ($item) => DsyncUserUpdatedDataEmail::fromArray($item), $data['emails']) : null, + jobTitle: $data['job_title'] ?? null, + username: $data['username'] ?? null, + role: isset($data['role']) ? SlimRole::fromArray($data['role']) : null, + roles: isset($data['roles']) ? array_map(fn ($item) => SlimRole::fromArray($item), $data['roles']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'directory_id' => $this->directoryId, + 'organization_id' => $this->organizationId, + 'idp_id' => $this->idpId, + 'email' => $this->email, + 'state' => $this->state->value, + 'raw_attributes' => $this->rawAttributes, + 'custom_attributes' => $this->customAttributes, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'first_name' => $this->firstName, + 'last_name' => $this->lastName, + 'emails' => $this->emails !== null ? array_map(fn ($item) => $item->toArray(), $this->emails) : null, + 'job_title' => $this->jobTitle, + 'username' => $this->username, + 'role' => $this->role?->toArray(), + 'roles' => $this->roles !== null ? array_map(fn ($item) => $item->toArray(), $this->roles) : null, + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/DsyncUserUpdatedDataEmail.php b/lib/Resource/DsyncUserUpdatedDataEmail.php new file mode 100644 index 00000000..2b6b9931 --- /dev/null +++ b/lib/Resource/DsyncUserUpdatedDataEmail.php @@ -0,0 +1,40 @@ + $this->primary, + 'type' => $this->type, + 'value' => $this->value, + ]; + } +} diff --git a/lib/Resource/DsyncUserUpdatedDataRole.php b/lib/Resource/DsyncUserUpdatedDataRole.php new file mode 100644 index 00000000..6a86ed56 --- /dev/null +++ b/lib/Resource/DsyncUserUpdatedDataRole.php @@ -0,0 +1,33 @@ + $this->slug, + ]; + } +} diff --git a/lib/Resource/EmailChange.php b/lib/Resource/EmailChange.php new file mode 100644 index 00000000..bd9da26b --- /dev/null +++ b/lib/Resource/EmailChange.php @@ -0,0 +1,47 @@ + $this->object, + 'user' => $this->user->toArray(), + 'new_email' => $this->newEmail, + 'expires_at' => $this->expiresAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/EmailChangeConfirmation.php b/lib/Resource/EmailChangeConfirmation.php new file mode 100644 index 00000000..0b898086 --- /dev/null +++ b/lib/Resource/EmailChangeConfirmation.php @@ -0,0 +1,36 @@ + $this->object, + 'user' => $this->user->toArray(), + ]; + } +} diff --git a/lib/Resource/EmailChangeConfirmationUser.php b/lib/Resource/EmailChangeConfirmationUser.php new file mode 100644 index 00000000..65b752dd --- /dev/null +++ b/lib/Resource/EmailChangeConfirmationUser.php @@ -0,0 +1,84 @@ +|null + */ + public ?array $metadata = null, + /** The user's preferred locale. */ + public ?string $locale = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + firstName: $data['first_name'] ?? null, + lastName: $data['last_name'] ?? null, + profilePictureUrl: $data['profile_picture_url'] ?? null, + email: $data['email'], + emailVerified: $data['email_verified'], + externalId: $data['external_id'] ?? null, + lastSignInAt: isset($data['last_sign_in_at']) ? new \DateTimeImmutable($data['last_sign_in_at']) : null, + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + metadata: $data['metadata'] ?? null, + locale: $data['locale'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'first_name' => $this->firstName, + 'last_name' => $this->lastName, + 'profile_picture_url' => $this->profilePictureUrl, + 'email' => $this->email, + 'email_verified' => $this->emailVerified, + 'external_id' => $this->externalId, + 'last_sign_in_at' => $this->lastSignInAt?->format(\DateTimeInterface::RFC3339_EXTENDED), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'metadata' => $this->metadata, + 'locale' => $this->locale, + ]; + } +} diff --git a/lib/Resource/EmailVerification.php b/lib/Resource/EmailVerification.php index 428c84f7..28a25f84 100644 --- a/lib/Resource/EmailVerification.php +++ b/lib/Resource/EmailVerification.php @@ -1,34 +1,60 @@ "object", - "id" => "id", - "user_id" => "userId", - "email" => "email", - "expires_at" => "expiresAt", - "code" => "code", - "created_at" => "createdAt", - "updated_at" => "updatedAt" - ]; + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'user_id' => $this->userId, + 'email' => $this->email, + 'expires_at' => $this->expiresAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'code' => $this->code, + ]; + } } diff --git a/lib/Resource/EmailVerificationCodeSessionAuthenticateRequest.php b/lib/Resource/EmailVerificationCodeSessionAuthenticateRequest.php new file mode 100644 index 00000000..7dbfa76c --- /dev/null +++ b/lib/Resource/EmailVerificationCodeSessionAuthenticateRequest.php @@ -0,0 +1,59 @@ + $this->clientId, + 'client_secret' => $this->clientSecret, + 'grant_type' => $this->grantType, + 'code' => $this->code, + 'pending_authentication_token' => $this->pendingAuthenticationToken, + 'ip_address' => $this->ipAddress, + 'device_id' => $this->deviceId, + 'user_agent' => $this->userAgent, + ]; + } +} diff --git a/lib/Resource/EmailVerificationCreated.php b/lib/Resource/EmailVerificationCreated.php new file mode 100644 index 00000000..2f2e160a --- /dev/null +++ b/lib/Resource/EmailVerificationCreated.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/EmailVerificationCreatedContext.php b/lib/Resource/EmailVerificationCreatedContext.php new file mode 100644 index 00000000..9ea3907a --- /dev/null +++ b/lib/Resource/EmailVerificationCreatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?EmailVerificationCreatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? EmailVerificationCreatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/EmailVerificationCreatedContextActor.php b/lib/Resource/EmailVerificationCreatedContextActor.php new file mode 100644 index 00000000..21f8d34b --- /dev/null +++ b/lib/Resource/EmailVerificationCreatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/EmailVerificationCreatedContextGoogleAnalyticsSession.php b/lib/Resource/EmailVerificationCreatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..6020e445 --- /dev/null +++ b/lib/Resource/EmailVerificationCreatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/EmailVerificationCreatedData.php b/lib/Resource/EmailVerificationCreatedData.php new file mode 100644 index 00000000..f34ecbd5 --- /dev/null +++ b/lib/Resource/EmailVerificationCreatedData.php @@ -0,0 +1,57 @@ + $this->object, + 'id' => $this->id, + 'user_id' => $this->userId, + 'email' => $this->email, + 'expires_at' => $this->expiresAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/EnrollUserAuthenticationFactor.php b/lib/Resource/EnrollUserAuthenticationFactor.php new file mode 100644 index 00000000..9ae42b76 --- /dev/null +++ b/lib/Resource/EnrollUserAuthenticationFactor.php @@ -0,0 +1,44 @@ + $this->type, + 'totp_issuer' => $this->totpIssuer, + 'totp_user' => $this->totpUser, + 'totp_secret' => $this->totpSecret, + ]; + } +} diff --git a/lib/Resource/EventContext.php b/lib/Resource/EventContext.php new file mode 100644 index 00000000..de84206b --- /dev/null +++ b/lib/Resource/EventContext.php @@ -0,0 +1,58 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + public ?EventContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: isset($data['google_analytics_sessions']) ? array_map(fn ($item) => EventContextGoogleAnalyticsSession::fromArray($item), $data['google_analytics_sessions']) : null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? EventContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/EventContextActor.php b/lib/Resource/EventContextActor.php new file mode 100644 index 00000000..0eca7b6d --- /dev/null +++ b/lib/Resource/EventContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/EventContextActorSource.php b/lib/Resource/EventContextActorSource.php new file mode 100644 index 00000000..1fcc2a21 --- /dev/null +++ b/lib/Resource/EventContextActorSource.php @@ -0,0 +1,14 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/EventListListMetadata.php b/lib/Resource/EventListListMetadata.php new file mode 100644 index 00000000..2f63d189 --- /dev/null +++ b/lib/Resource/EventListListMetadata.php @@ -0,0 +1,33 @@ + $this->after, + ]; + } +} diff --git a/lib/Resource/EventSchema.php b/lib/Resource/EventSchema.php new file mode 100644 index 00000000..dc91b44f --- /dev/null +++ b/lib/Resource/EventSchema.php @@ -0,0 +1,59 @@ + + */ + public array $data, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** + * Additional context about the event. + * @var array|null + */ + public ?array $context = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + event: $data['event'], + data: $data['data'], + createdAt: new \DateTimeImmutable($data['created_at']), + context: $data['context'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'event' => $this->event, + 'data' => $this->data, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'context' => $this->context, + ]; + } +} diff --git a/lib/Resource/EventsOrder.php b/lib/Resource/EventsOrder.php new file mode 100644 index 00000000..15232a27 --- /dev/null +++ b/lib/Resource/EventsOrder.php @@ -0,0 +1,14 @@ + $this->redirectUri, + ]; + } +} diff --git a/lib/Resource/FeatureFlag.php b/lib/Resource/FeatureFlag.php index 8c58a7cf..79b16311 100644 --- a/lib/Resource/FeatureFlag.php +++ b/lib/Resource/FeatureFlag.php @@ -1,37 +1,75 @@ + */ + public array $tags, + /** Specifies whether the Feature Flag is active for the current environment. */ + public bool $enabled, + /** The value returned for users and organizations who don't match any configured targeting rules. */ + public bool $defaultValue, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + ) { + } - public const RESOURCE_ATTRIBUTES = [ - "id", - "slug", - "name", - "description", - "createdAt", - "updatedAt" - ]; + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + slug: $data['slug'], + name: $data['name'], + description: $data['description'] ?? null, + owner: isset($data['owner']) ? FeatureFlagOwner::fromArray($data['owner']) : null, + tags: $data['tags'], + enabled: $data['enabled'], + defaultValue: $data['default_value'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + ); + } - public const RESPONSE_TO_RESOURCE_KEY = [ - "id" => "id", - "slug" => "slug", - "name" => "name", - "description" => "description", - "created_at" => "createdAt", - "updated_at" => "updatedAt" - ]; + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'slug' => $this->slug, + 'name' => $this->name, + 'description' => $this->description, + 'owner' => $this->owner?->toArray(), + 'tags' => $this->tags, + 'enabled' => $this->enabled, + 'default_value' => $this->defaultValue, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } } diff --git a/lib/Resource/FeatureFlagOwner.php b/lib/Resource/FeatureFlagOwner.php new file mode 100644 index 00000000..4376ac3b --- /dev/null +++ b/lib/Resource/FeatureFlagOwner.php @@ -0,0 +1,40 @@ + $this->email, + 'first_name' => $this->firstName, + 'last_name' => $this->lastName, + ]; + } +} diff --git a/lib/Resource/FeatureFlagsOrder.php b/lib/Resource/FeatureFlagsOrder.php new file mode 100644 index 00000000..a043b1b5 --- /dev/null +++ b/lib/Resource/FeatureFlagsOrder.php @@ -0,0 +1,14 @@ + + */ + public array $tags, + /** Specifies whether the Feature Flag is active for the current environment. */ + public bool $enabled, + /** The value returned for users and organizations who don't match any configured targeting rules. */ + public bool $defaultValue, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + slug: $data['slug'], + name: $data['name'], + description: $data['description'] ?? null, + owner: isset($data['owner']) ? FlagOwner::fromArray($data['owner']) : null, + tags: $data['tags'], + enabled: $data['enabled'], + defaultValue: $data['default_value'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'slug' => $this->slug, + 'name' => $this->name, + 'description' => $this->description, + 'owner' => $this->owner?->toArray(), + 'tags' => $this->tags, + 'enabled' => $this->enabled, + 'default_value' => $this->defaultValue, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/FlagCreated.php b/lib/Resource/FlagCreated.php new file mode 100644 index 00000000..7724de95 --- /dev/null +++ b/lib/Resource/FlagCreated.php @@ -0,0 +1,51 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'context' => $this->context->toArray(), + 'object' => $this->object, + ]; + } +} diff --git a/lib/Resource/FlagCreatedContext.php b/lib/Resource/FlagCreatedContext.php new file mode 100644 index 00000000..2c0d130d --- /dev/null +++ b/lib/Resource/FlagCreatedContext.php @@ -0,0 +1,37 @@ + $this->clientId, + 'actor' => $this->actor->toArray(), + ]; + } +} diff --git a/lib/Resource/FlagCreatedContextActor.php b/lib/Resource/FlagCreatedContextActor.php new file mode 100644 index 00000000..95947d5e --- /dev/null +++ b/lib/Resource/FlagCreatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/FlagCreatedContextActorSource.php b/lib/Resource/FlagCreatedContextActorSource.php new file mode 100644 index 00000000..0a6bce24 --- /dev/null +++ b/lib/Resource/FlagCreatedContextActorSource.php @@ -0,0 +1,14 @@ + + */ + public array $tags, + /** Specifies whether the Feature Flag is active for the current environment. */ + public bool $enabled, + /** The value returned for users and organizations who don't match any configured targeting rules. */ + public bool $defaultValue, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + environmentId: $data['environment_id'], + slug: $data['slug'], + name: $data['name'], + description: $data['description'] ?? null, + owner: isset($data['owner']) ? FlagCreatedDataOwner::fromArray($data['owner']) : null, + tags: $data['tags'], + enabled: $data['enabled'], + defaultValue: $data['default_value'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'environment_id' => $this->environmentId, + 'slug' => $this->slug, + 'name' => $this->name, + 'description' => $this->description, + 'owner' => $this->owner?->toArray(), + 'tags' => $this->tags, + 'enabled' => $this->enabled, + 'default_value' => $this->defaultValue, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/FlagCreatedDataOwner.php b/lib/Resource/FlagCreatedDataOwner.php new file mode 100644 index 00000000..d480281b --- /dev/null +++ b/lib/Resource/FlagCreatedDataOwner.php @@ -0,0 +1,40 @@ + $this->email, + 'first_name' => $this->firstName, + 'last_name' => $this->lastName, + ]; + } +} diff --git a/lib/Resource/FlagDeleted.php b/lib/Resource/FlagDeleted.php new file mode 100644 index 00000000..2dcfedfa --- /dev/null +++ b/lib/Resource/FlagDeleted.php @@ -0,0 +1,51 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'context' => $this->context->toArray(), + 'object' => $this->object, + ]; + } +} diff --git a/lib/Resource/FlagDeletedContext.php b/lib/Resource/FlagDeletedContext.php new file mode 100644 index 00000000..a23a3ac6 --- /dev/null +++ b/lib/Resource/FlagDeletedContext.php @@ -0,0 +1,37 @@ + $this->clientId, + 'actor' => $this->actor->toArray(), + ]; + } +} diff --git a/lib/Resource/FlagDeletedContextActor.php b/lib/Resource/FlagDeletedContextActor.php new file mode 100644 index 00000000..1c98e7da --- /dev/null +++ b/lib/Resource/FlagDeletedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/FlagDeletedData.php b/lib/Resource/FlagDeletedData.php new file mode 100644 index 00000000..67b6309b --- /dev/null +++ b/lib/Resource/FlagDeletedData.php @@ -0,0 +1,79 @@ + + */ + public array $tags, + /** Specifies whether the Feature Flag is active for the current environment. */ + public bool $enabled, + /** The value returned for users and organizations who don't match any configured targeting rules. */ + public bool $defaultValue, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + environmentId: $data['environment_id'], + slug: $data['slug'], + name: $data['name'], + description: $data['description'] ?? null, + owner: isset($data['owner']) ? FlagDeletedDataOwner::fromArray($data['owner']) : null, + tags: $data['tags'], + enabled: $data['enabled'], + defaultValue: $data['default_value'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'environment_id' => $this->environmentId, + 'slug' => $this->slug, + 'name' => $this->name, + 'description' => $this->description, + 'owner' => $this->owner?->toArray(), + 'tags' => $this->tags, + 'enabled' => $this->enabled, + 'default_value' => $this->defaultValue, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/FlagDeletedDataOwner.php b/lib/Resource/FlagDeletedDataOwner.php new file mode 100644 index 00000000..02a73a85 --- /dev/null +++ b/lib/Resource/FlagDeletedDataOwner.php @@ -0,0 +1,40 @@ + $this->email, + 'first_name' => $this->firstName, + 'last_name' => $this->lastName, + ]; + } +} diff --git a/lib/Resource/FlagOwner.php b/lib/Resource/FlagOwner.php new file mode 100644 index 00000000..9bfdcce1 --- /dev/null +++ b/lib/Resource/FlagOwner.php @@ -0,0 +1,40 @@ + $this->email, + 'first_name' => $this->firstName, + 'last_name' => $this->lastName, + ]; + } +} diff --git a/lib/Resource/FlagRuleUpdated.php b/lib/Resource/FlagRuleUpdated.php new file mode 100644 index 00000000..12613d66 --- /dev/null +++ b/lib/Resource/FlagRuleUpdated.php @@ -0,0 +1,51 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'context' => $this->context->toArray(), + 'object' => $this->object, + ]; + } +} diff --git a/lib/Resource/FlagRuleUpdatedContext.php b/lib/Resource/FlagRuleUpdatedContext.php new file mode 100644 index 00000000..c4127413 --- /dev/null +++ b/lib/Resource/FlagRuleUpdatedContext.php @@ -0,0 +1,49 @@ + $this->clientId, + 'actor' => $this->actor->toArray(), + 'access_type' => $this->accessType->value, + 'configured_targets' => $this->configuredTargets->toArray(), + 'previous_attributes' => $this->previousAttributes->toArray(), + ]; + } +} diff --git a/lib/Resource/FlagRuleUpdatedContextAccessType.php b/lib/Resource/FlagRuleUpdatedContextAccessType.php new file mode 100644 index 00000000..d858bd5f --- /dev/null +++ b/lib/Resource/FlagRuleUpdatedContextAccessType.php @@ -0,0 +1,14 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/FlagRuleUpdatedContextConfiguredTarget.php b/lib/Resource/FlagRuleUpdatedContextConfiguredTarget.php new file mode 100644 index 00000000..dd264b8b --- /dev/null +++ b/lib/Resource/FlagRuleUpdatedContextConfiguredTarget.php @@ -0,0 +1,43 @@ + + */ + public array $organizations, + /** + * The users targeted by the flag rule. + * @var array<\WorkOS\Resource\FlagRuleUpdatedContextConfiguredTargetUser> + */ + public array $users, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + organizations: array_map(fn ($item) => FlagRuleUpdatedContextConfiguredTargetOrganization::fromArray($item), $data['organizations']), + users: array_map(fn ($item) => FlagRuleUpdatedContextConfiguredTargetUser::fromArray($item), $data['users']), + ); + } + + public function toArray(): array + { + return [ + 'organizations' => array_map(fn ($item) => $item->toArray(), $this->organizations), + 'users' => array_map(fn ($item) => $item->toArray(), $this->users), + ]; + } +} diff --git a/lib/Resource/FlagRuleUpdatedContextConfiguredTargetOrganization.php b/lib/Resource/FlagRuleUpdatedContextConfiguredTargetOrganization.php new file mode 100644 index 00000000..7230cfad --- /dev/null +++ b/lib/Resource/FlagRuleUpdatedContextConfiguredTargetOrganization.php @@ -0,0 +1,36 @@ + $this->id, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/FlagRuleUpdatedContextConfiguredTargetUser.php b/lib/Resource/FlagRuleUpdatedContextConfiguredTargetUser.php new file mode 100644 index 00000000..deb63d5c --- /dev/null +++ b/lib/Resource/FlagRuleUpdatedContextConfiguredTargetUser.php @@ -0,0 +1,36 @@ + $this->id, + 'email' => $this->email, + ]; + } +} diff --git a/lib/Resource/FlagRuleUpdatedContextPreviousAttribute.php b/lib/Resource/FlagRuleUpdatedContextPreviousAttribute.php new file mode 100644 index 00000000..4fd8fcf3 --- /dev/null +++ b/lib/Resource/FlagRuleUpdatedContextPreviousAttribute.php @@ -0,0 +1,37 @@ + $this->data?->toArray(), + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/FlagRuleUpdatedContextPreviousAttributeContext.php b/lib/Resource/FlagRuleUpdatedContextPreviousAttributeContext.php new file mode 100644 index 00000000..d3116bca --- /dev/null +++ b/lib/Resource/FlagRuleUpdatedContextPreviousAttributeContext.php @@ -0,0 +1,37 @@ + $this->accessType?->value, + 'configured_targets' => $this->configuredTargets?->toArray(), + ]; + } +} diff --git a/lib/Resource/FlagRuleUpdatedContextPreviousAttributeContextConfiguredTarget.php b/lib/Resource/FlagRuleUpdatedContextPreviousAttributeContextConfiguredTarget.php new file mode 100644 index 00000000..229b04c9 --- /dev/null +++ b/lib/Resource/FlagRuleUpdatedContextPreviousAttributeContextConfiguredTarget.php @@ -0,0 +1,43 @@ + + */ + public array $organizations, + /** + * The users targeted by the flag rule. + * @var array<\WorkOS\Resource\FlagRuleUpdatedContextPreviousAttributeContextConfiguredTargetUser> + */ + public array $users, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + organizations: array_map(fn ($item) => FlagRuleUpdatedContextPreviousAttributeContextConfiguredTargetOrganization::fromArray($item), $data['organizations']), + users: array_map(fn ($item) => FlagRuleUpdatedContextPreviousAttributeContextConfiguredTargetUser::fromArray($item), $data['users']), + ); + } + + public function toArray(): array + { + return [ + 'organizations' => array_map(fn ($item) => $item->toArray(), $this->organizations), + 'users' => array_map(fn ($item) => $item->toArray(), $this->users), + ]; + } +} diff --git a/lib/Resource/FlagRuleUpdatedContextPreviousAttributeContextConfiguredTargetOrganization.php b/lib/Resource/FlagRuleUpdatedContextPreviousAttributeContextConfiguredTargetOrganization.php new file mode 100644 index 00000000..bfaf7d0b --- /dev/null +++ b/lib/Resource/FlagRuleUpdatedContextPreviousAttributeContextConfiguredTargetOrganization.php @@ -0,0 +1,36 @@ + $this->id, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/FlagRuleUpdatedContextPreviousAttributeContextConfiguredTargetUser.php b/lib/Resource/FlagRuleUpdatedContextPreviousAttributeContextConfiguredTargetUser.php new file mode 100644 index 00000000..2b288b3d --- /dev/null +++ b/lib/Resource/FlagRuleUpdatedContextPreviousAttributeContextConfiguredTargetUser.php @@ -0,0 +1,36 @@ + $this->id, + 'email' => $this->email, + ]; + } +} diff --git a/lib/Resource/FlagRuleUpdatedContextPreviousAttributeData.php b/lib/Resource/FlagRuleUpdatedContextPreviousAttributeData.php new file mode 100644 index 00000000..983de1ed --- /dev/null +++ b/lib/Resource/FlagRuleUpdatedContextPreviousAttributeData.php @@ -0,0 +1,37 @@ + $this->enabled, + 'default_value' => $this->defaultValue, + ]; + } +} diff --git a/lib/Resource/FlagRuleUpdatedData.php b/lib/Resource/FlagRuleUpdatedData.php new file mode 100644 index 00000000..78b101b4 --- /dev/null +++ b/lib/Resource/FlagRuleUpdatedData.php @@ -0,0 +1,79 @@ + + */ + public array $tags, + /** Specifies whether the Feature Flag is active for the current environment. */ + public bool $enabled, + /** The value returned for users and organizations who don't match any configured targeting rules. */ + public bool $defaultValue, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + environmentId: $data['environment_id'], + slug: $data['slug'], + name: $data['name'], + description: $data['description'] ?? null, + owner: isset($data['owner']) ? FlagRuleUpdatedDataOwner::fromArray($data['owner']) : null, + tags: $data['tags'], + enabled: $data['enabled'], + defaultValue: $data['default_value'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'environment_id' => $this->environmentId, + 'slug' => $this->slug, + 'name' => $this->name, + 'description' => $this->description, + 'owner' => $this->owner?->toArray(), + 'tags' => $this->tags, + 'enabled' => $this->enabled, + 'default_value' => $this->defaultValue, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/FlagRuleUpdatedDataOwner.php b/lib/Resource/FlagRuleUpdatedDataOwner.php new file mode 100644 index 00000000..541d38bc --- /dev/null +++ b/lib/Resource/FlagRuleUpdatedDataOwner.php @@ -0,0 +1,40 @@ + $this->email, + 'first_name' => $this->firstName, + 'last_name' => $this->lastName, + ]; + } +} diff --git a/lib/Resource/FlagUpdated.php b/lib/Resource/FlagUpdated.php new file mode 100644 index 00000000..a45490e6 --- /dev/null +++ b/lib/Resource/FlagUpdated.php @@ -0,0 +1,51 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'context' => $this->context->toArray(), + 'object' => $this->object, + ]; + } +} diff --git a/lib/Resource/FlagUpdatedContext.php b/lib/Resource/FlagUpdatedContext.php new file mode 100644 index 00000000..79dfbb1c --- /dev/null +++ b/lib/Resource/FlagUpdatedContext.php @@ -0,0 +1,41 @@ + $this->clientId, + 'actor' => $this->actor->toArray(), + 'previous_attributes' => $this->previousAttributes?->toArray(), + ]; + } +} diff --git a/lib/Resource/FlagUpdatedContextActor.php b/lib/Resource/FlagUpdatedContextActor.php new file mode 100644 index 00000000..bf32f898 --- /dev/null +++ b/lib/Resource/FlagUpdatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/FlagUpdatedContextPreviousAttribute.php b/lib/Resource/FlagUpdatedContextPreviousAttribute.php new file mode 100644 index 00000000..a8cc5da7 --- /dev/null +++ b/lib/Resource/FlagUpdatedContextPreviousAttribute.php @@ -0,0 +1,33 @@ + $this->data?->toArray(), + ]; + } +} diff --git a/lib/Resource/FlagUpdatedContextPreviousAttributeData.php b/lib/Resource/FlagUpdatedContextPreviousAttributeData.php new file mode 100644 index 00000000..f090724a --- /dev/null +++ b/lib/Resource/FlagUpdatedContextPreviousAttributeData.php @@ -0,0 +1,52 @@ +|null + */ + public ?array $tags = null, + /** Whether the flag was previously enabled. */ + public ?bool $enabled = null, + /** The previous default value of the flag. */ + public ?bool $defaultValue = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + name: $data['name'] ?? null, + description: $data['description'] ?? null, + tags: $data['tags'] ?? null, + enabled: $data['enabled'] ?? null, + defaultValue: $data['default_value'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'name' => $this->name, + 'description' => $this->description, + 'tags' => $this->tags, + 'enabled' => $this->enabled, + 'default_value' => $this->defaultValue, + ]; + } +} diff --git a/lib/Resource/FlagUpdatedData.php b/lib/Resource/FlagUpdatedData.php new file mode 100644 index 00000000..90609193 --- /dev/null +++ b/lib/Resource/FlagUpdatedData.php @@ -0,0 +1,79 @@ + + */ + public array $tags, + /** Specifies whether the Feature Flag is active for the current environment. */ + public bool $enabled, + /** The value returned for users and organizations who don't match any configured targeting rules. */ + public bool $defaultValue, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + environmentId: $data['environment_id'], + slug: $data['slug'], + name: $data['name'], + description: $data['description'] ?? null, + owner: isset($data['owner']) ? FlagUpdatedDataOwner::fromArray($data['owner']) : null, + tags: $data['tags'], + enabled: $data['enabled'], + defaultValue: $data['default_value'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'environment_id' => $this->environmentId, + 'slug' => $this->slug, + 'name' => $this->name, + 'description' => $this->description, + 'owner' => $this->owner?->toArray(), + 'tags' => $this->tags, + 'enabled' => $this->enabled, + 'default_value' => $this->defaultValue, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/FlagUpdatedDataOwner.php b/lib/Resource/FlagUpdatedDataOwner.php new file mode 100644 index 00000000..d943b6d7 --- /dev/null +++ b/lib/Resource/FlagUpdatedDataOwner.php @@ -0,0 +1,40 @@ + $this->email, + 'first_name' => $this->firstName, + 'last_name' => $this->lastName, + ]; + } +} diff --git a/lib/Resource/GenerateLink.php b/lib/Resource/GenerateLink.php new file mode 100644 index 00000000..7ef31908 --- /dev/null +++ b/lib/Resource/GenerateLink.php @@ -0,0 +1,65 @@ +|null + */ + public ?array $adminEmails = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + organization: $data['organization'], + returnUrl: $data['return_url'] ?? null, + successUrl: $data['success_url'] ?? null, + intent: isset($data['intent']) ? GenerateLinkIntent::from($data['intent']) : null, + intentOptions: isset($data['intent_options']) ? IntentOptions::fromArray($data['intent_options']) : null, + adminEmails: $data['admin_emails'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'organization' => $this->organization, + 'return_url' => $this->returnUrl, + 'success_url' => $this->successUrl, + 'intent' => $this->intent?->value, + 'intent_options' => $this->intentOptions?->toArray(), + 'admin_emails' => $this->adminEmails, + ]; + } +} diff --git a/lib/Resource/GenerateLinkIntent.php b/lib/Resource/GenerateLinkIntent.php new file mode 100644 index 00000000..35e737e2 --- /dev/null +++ b/lib/Resource/GenerateLinkIntent.php @@ -0,0 +1,18 @@ + "email", - "reason" => "reason", - ]; -} diff --git a/lib/Resource/IntentOptions.php b/lib/Resource/IntentOptions.php new file mode 100644 index 00000000..c49652f1 --- /dev/null +++ b/lib/Resource/IntentOptions.php @@ -0,0 +1,32 @@ + $this->sso->toArray(), + ]; + } +} diff --git a/lib/Resource/Invitation.php b/lib/Resource/Invitation.php index 496c0ead..326c423d 100644 --- a/lib/Resource/Invitation.php +++ b/lib/Resource/Invitation.php @@ -1,44 +1,84 @@ "object", - "id" => "id", - "email" => "email", - "state" => "state", - "accepted_at" => "acceptedAt", - "revoked_at" => "revokedAt", - "expires_at" => "expiresAt", - "token" => "token", - "accept_invitation_url" => "acceptInvitationUrl", - "organization_id" => "organizationId", - "inviter_user_id" => "inviterUserId", - "created_at" => "createdAt", - "updated_at" => "updatedAt" - ]; + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'email' => $this->email, + 'state' => $this->state->value, + 'accepted_at' => $this->acceptedAt?->format(\DateTimeInterface::RFC3339_EXTENDED), + 'revoked_at' => $this->revokedAt?->format(\DateTimeInterface::RFC3339_EXTENDED), + 'expires_at' => $this->expiresAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'organization_id' => $this->organizationId, + 'inviter_user_id' => $this->inviterUserId, + 'accepted_user_id' => $this->acceptedUserId, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'token' => $this->token, + 'accept_invitation_url' => $this->acceptInvitationUrl, + ]; + } } diff --git a/lib/Resource/InvitationAccepted.php b/lib/Resource/InvitationAccepted.php new file mode 100644 index 00000000..aaeb03a3 --- /dev/null +++ b/lib/Resource/InvitationAccepted.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/InvitationAcceptedContext.php b/lib/Resource/InvitationAcceptedContext.php new file mode 100644 index 00000000..d2eba73b --- /dev/null +++ b/lib/Resource/InvitationAcceptedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?InvitationAcceptedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? InvitationAcceptedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/InvitationAcceptedContextActor.php b/lib/Resource/InvitationAcceptedContextActor.php new file mode 100644 index 00000000..604567ec --- /dev/null +++ b/lib/Resource/InvitationAcceptedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/InvitationAcceptedContextGoogleAnalyticsSession.php b/lib/Resource/InvitationAcceptedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..4cd7377f --- /dev/null +++ b/lib/Resource/InvitationAcceptedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/InvitationAcceptedData.php b/lib/Resource/InvitationAcceptedData.php new file mode 100644 index 00000000..37ab7c6d --- /dev/null +++ b/lib/Resource/InvitationAcceptedData.php @@ -0,0 +1,77 @@ + $this->object, + 'id' => $this->id, + 'email' => $this->email, + 'state' => $this->state->value, + 'accepted_at' => $this->acceptedAt?->format(\DateTimeInterface::RFC3339_EXTENDED), + 'revoked_at' => $this->revokedAt?->format(\DateTimeInterface::RFC3339_EXTENDED), + 'expires_at' => $this->expiresAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'organization_id' => $this->organizationId, + 'inviter_user_id' => $this->inviterUserId, + 'accepted_user_id' => $this->acceptedUserId, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/InvitationCreated.php b/lib/Resource/InvitationCreated.php new file mode 100644 index 00000000..a1e8d7f8 --- /dev/null +++ b/lib/Resource/InvitationCreated.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/InvitationCreatedContext.php b/lib/Resource/InvitationCreatedContext.php new file mode 100644 index 00000000..99041bc8 --- /dev/null +++ b/lib/Resource/InvitationCreatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?InvitationCreatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? InvitationCreatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/InvitationCreatedContextActor.php b/lib/Resource/InvitationCreatedContextActor.php new file mode 100644 index 00000000..1bd6928a --- /dev/null +++ b/lib/Resource/InvitationCreatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/InvitationCreatedContextGoogleAnalyticsSession.php b/lib/Resource/InvitationCreatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..3c3689bc --- /dev/null +++ b/lib/Resource/InvitationCreatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/InvitationCreatedData.php b/lib/Resource/InvitationCreatedData.php new file mode 100644 index 00000000..b6e91def --- /dev/null +++ b/lib/Resource/InvitationCreatedData.php @@ -0,0 +1,77 @@ + $this->object, + 'id' => $this->id, + 'email' => $this->email, + 'state' => $this->state->value, + 'accepted_at' => $this->acceptedAt?->format(\DateTimeInterface::RFC3339_EXTENDED), + 'revoked_at' => $this->revokedAt?->format(\DateTimeInterface::RFC3339_EXTENDED), + 'expires_at' => $this->expiresAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'organization_id' => $this->organizationId, + 'inviter_user_id' => $this->inviterUserId, + 'accepted_user_id' => $this->acceptedUserId, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/InvitationResent.php b/lib/Resource/InvitationResent.php new file mode 100644 index 00000000..d861f89d --- /dev/null +++ b/lib/Resource/InvitationResent.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/InvitationResentContext.php b/lib/Resource/InvitationResentContext.php new file mode 100644 index 00000000..5c75bfb0 --- /dev/null +++ b/lib/Resource/InvitationResentContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?InvitationResentContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? InvitationResentContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/InvitationResentContextActor.php b/lib/Resource/InvitationResentContextActor.php new file mode 100644 index 00000000..89a79c23 --- /dev/null +++ b/lib/Resource/InvitationResentContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/InvitationResentContextGoogleAnalyticsSession.php b/lib/Resource/InvitationResentContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..ba9fb0df --- /dev/null +++ b/lib/Resource/InvitationResentContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/InvitationResentData.php b/lib/Resource/InvitationResentData.php new file mode 100644 index 00000000..6f47bc4f --- /dev/null +++ b/lib/Resource/InvitationResentData.php @@ -0,0 +1,77 @@ + $this->object, + 'id' => $this->id, + 'email' => $this->email, + 'state' => $this->state->value, + 'accepted_at' => $this->acceptedAt?->format(\DateTimeInterface::RFC3339_EXTENDED), + 'revoked_at' => $this->revokedAt?->format(\DateTimeInterface::RFC3339_EXTENDED), + 'expires_at' => $this->expiresAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'organization_id' => $this->organizationId, + 'inviter_user_id' => $this->inviterUserId, + 'accepted_user_id' => $this->acceptedUserId, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/InvitationRevoked.php b/lib/Resource/InvitationRevoked.php new file mode 100644 index 00000000..8ad38510 --- /dev/null +++ b/lib/Resource/InvitationRevoked.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/InvitationRevokedContext.php b/lib/Resource/InvitationRevokedContext.php new file mode 100644 index 00000000..f732ce41 --- /dev/null +++ b/lib/Resource/InvitationRevokedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?InvitationRevokedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? InvitationRevokedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/InvitationRevokedContextActor.php b/lib/Resource/InvitationRevokedContextActor.php new file mode 100644 index 00000000..898b4b44 --- /dev/null +++ b/lib/Resource/InvitationRevokedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/InvitationRevokedContextGoogleAnalyticsSession.php b/lib/Resource/InvitationRevokedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..4778aac4 --- /dev/null +++ b/lib/Resource/InvitationRevokedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/InvitationRevokedData.php b/lib/Resource/InvitationRevokedData.php new file mode 100644 index 00000000..e5649273 --- /dev/null +++ b/lib/Resource/InvitationRevokedData.php @@ -0,0 +1,77 @@ + $this->object, + 'id' => $this->id, + 'email' => $this->email, + 'state' => $this->state->value, + 'accepted_at' => $this->acceptedAt?->format(\DateTimeInterface::RFC3339_EXTENDED), + 'revoked_at' => $this->revokedAt?->format(\DateTimeInterface::RFC3339_EXTENDED), + 'expires_at' => $this->expiresAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'organization_id' => $this->organizationId, + 'inviter_user_id' => $this->inviterUserId, + 'accepted_user_id' => $this->acceptedUserId, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/InvitationState.php b/lib/Resource/InvitationState.php new file mode 100644 index 00000000..fe4aa8e2 --- /dev/null +++ b/lib/Resource/InvitationState.php @@ -0,0 +1,15 @@ + $this->object, + 'content' => $this->content, + 'created_at' => $this->createdAt, + 'updated_at' => $this->updatedAt, + ]; + } +} diff --git a/lib/Resource/JsonSerializableTrait.php b/lib/Resource/JsonSerializableTrait.php new file mode 100644 index 00000000..b1c3602a --- /dev/null +++ b/lib/Resource/JsonSerializableTrait.php @@ -0,0 +1,15 @@ +toArray(); + } +} diff --git a/lib/Resource/JwksResponse.php b/lib/Resource/JwksResponse.php new file mode 100644 index 00000000..4c5a1427 --- /dev/null +++ b/lib/Resource/JwksResponse.php @@ -0,0 +1,35 @@ + + */ + public array $keys, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + keys: array_map(fn ($item) => JwksResponseKeys::fromArray($item), $data['keys']), + ); + } + + public function toArray(): array + { + return [ + 'keys' => array_map(fn ($item) => $item->toArray(), $this->keys), + ]; + } +} diff --git a/lib/Resource/JwksResponseKeys.php b/lib/Resource/JwksResponseKeys.php new file mode 100644 index 00000000..f59f4ef4 --- /dev/null +++ b/lib/Resource/JwksResponseKeys.php @@ -0,0 +1,63 @@ + + */ + public array $x5C, + /** RSA modulus. */ + public string $n, + /** RSA exponent. */ + public string $e, + /** Key ID. */ + public string $kid, + /** X.509 certificate SHA-256 thumbprint. */ + public string $x5TS256, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + alg: $data['alg'], + kty: $data['kty'], + use: $data['use'], + x5C: $data['x5c'], + n: $data['n'], + e: $data['e'], + kid: $data['kid'], + x5TS256: $data['x5t#S256'], + ); + } + + public function toArray(): array + { + return [ + 'alg' => $this->alg, + 'kty' => $this->kty, + 'use' => $this->use, + 'x5c' => $this->x5C, + 'n' => $this->n, + 'e' => $this->e, + 'kid' => $this->kid, + 'x5t#S256' => $this->x5TS256, + ]; + } +} diff --git a/lib/Resource/ListData.php b/lib/Resource/ListData.php new file mode 100644 index 00000000..3cec9dfe --- /dev/null +++ b/lib/Resource/ListData.php @@ -0,0 +1,71 @@ + + */ + public array $permissions, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + slug: $data['slug'], + object: $data['object'], + id: $data['id'], + name: $data['name'], + description: $data['description'] ?? null, + type: RoleType::from($data['type']), + resourceTypeSlug: $data['resource_type_slug'], + permissions: $data['permissions'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + ); + } + + public function toArray(): array + { + return [ + 'slug' => $this->slug, + 'object' => $this->object, + 'id' => $this->id, + 'name' => $this->name, + 'description' => $this->description, + 'type' => $this->type->value, + 'resource_type_slug' => $this->resourceTypeSlug, + 'permissions' => $this->permissions, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/ListDataType.php b/lib/Resource/ListDataType.php new file mode 100644 index 00000000..1219b29b --- /dev/null +++ b/lib/Resource/ListDataType.php @@ -0,0 +1,13 @@ + + */ + public array $data, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + data: array_map(fn ($item) => ListData::fromArray($item), $data['data']), + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'data' => array_map(fn ($item) => $item->toArray(), $this->data), + ]; + } +} diff --git a/lib/Resource/MFATotpSessionAuthenticateRequest.php b/lib/Resource/MFATotpSessionAuthenticateRequest.php new file mode 100644 index 00000000..b2e0b374 --- /dev/null +++ b/lib/Resource/MFATotpSessionAuthenticateRequest.php @@ -0,0 +1,63 @@ + $this->clientId, + 'client_secret' => $this->clientSecret, + 'grant_type' => $this->grantType, + 'code' => $this->code, + 'pending_authentication_token' => $this->pendingAuthenticationToken, + 'authentication_challenge_id' => $this->authenticationChallengeId, + 'ip_address' => $this->ipAddress, + 'device_id' => $this->deviceId, + 'user_agent' => $this->userAgent, + ]; + } +} diff --git a/lib/Resource/MagicAuth.php b/lib/Resource/MagicAuth.php index 9dbdce26..c63b9827 100644 --- a/lib/Resource/MagicAuth.php +++ b/lib/Resource/MagicAuth.php @@ -1,34 +1,60 @@ "object", - "id" => "id", - "user_id" => "userId", - "email" => "email", - "expires_at" => "expiresAt", - "code" => "code", - "created_at" => "createdAt", - "updated_at" => "updatedAt" - ]; + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'user_id' => $this->userId, + 'email' => $this->email, + 'expires_at' => $this->expiresAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'code' => $this->code, + ]; + } } diff --git a/lib/Resource/MagicAuthCodeSessionAuthenticateRequest.php b/lib/Resource/MagicAuthCodeSessionAuthenticateRequest.php new file mode 100644 index 00000000..1ab3e307 --- /dev/null +++ b/lib/Resource/MagicAuthCodeSessionAuthenticateRequest.php @@ -0,0 +1,63 @@ + $this->clientId, + 'client_secret' => $this->clientSecret, + 'grant_type' => $this->grantType, + 'code' => $this->code, + 'email' => $this->email, + 'invitation_token' => $this->invitationToken, + 'ip_address' => $this->ipAddress, + 'device_id' => $this->deviceId, + 'user_agent' => $this->userAgent, + ]; + } +} diff --git a/lib/Resource/MagicAuthCreated.php b/lib/Resource/MagicAuthCreated.php new file mode 100644 index 00000000..0b0dac52 --- /dev/null +++ b/lib/Resource/MagicAuthCreated.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/MagicAuthCreatedContext.php b/lib/Resource/MagicAuthCreatedContext.php new file mode 100644 index 00000000..5c703783 --- /dev/null +++ b/lib/Resource/MagicAuthCreatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?MagicAuthCreatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? MagicAuthCreatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/MagicAuthCreatedContextActor.php b/lib/Resource/MagicAuthCreatedContextActor.php new file mode 100644 index 00000000..61d8aea4 --- /dev/null +++ b/lib/Resource/MagicAuthCreatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/MagicAuthCreatedContextGoogleAnalyticsSession.php b/lib/Resource/MagicAuthCreatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..add9a254 --- /dev/null +++ b/lib/Resource/MagicAuthCreatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/MagicAuthCreatedData.php b/lib/Resource/MagicAuthCreatedData.php new file mode 100644 index 00000000..596573f1 --- /dev/null +++ b/lib/Resource/MagicAuthCreatedData.php @@ -0,0 +1,57 @@ + $this->object, + 'id' => $this->id, + 'user_id' => $this->userId, + 'email' => $this->email, + 'expires_at' => $this->expiresAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/NewConnectApplicationSecret.php b/lib/Resource/NewConnectApplicationSecret.php new file mode 100644 index 00000000..a6a8c294 --- /dev/null +++ b/lib/Resource/NewConnectApplicationSecret.php @@ -0,0 +1,56 @@ + $this->object, + 'id' => $this->id, + 'secret_hint' => $this->secretHint, + 'last_used_at' => $this->lastUsedAt, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'secret' => $this->secret, + ]; + } +} diff --git a/lib/Resource/OAuthTokens.php b/lib/Resource/OAuthTokens.php deleted file mode 100644 index ac92c714..00000000 --- a/lib/Resource/OAuthTokens.php +++ /dev/null @@ -1,40 +0,0 @@ - "accessToken", - "refresh_token" => "refreshToken", - "expires_at" => "expiresAt", - "scopes" => "scopes" - ]; - - public static function constructFromResponse($response) - { - $instance = parent::constructFromResponse($response); - - // Ensure scopes is always an array - if (!isset($instance->values["scopes"])) { - $instance->values["scopes"] = []; - } - - return $instance; - } -} diff --git a/lib/Resource/Order.php b/lib/Resource/Order.php deleted file mode 100644 index 03f28787..00000000 --- a/lib/Resource/Order.php +++ /dev/null @@ -1,14 +0,0 @@ - + */ + public array $domains, + /** + * Object containing [metadata](https://workos.com/docs/authkit/metadata) key/value pairs associated with the Organization. + * @var array + */ + public array $metadata, + /** The external ID of the Organization. */ + public ?string $externalId, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + /** The Stripe customer ID of the Organization. */ + public ?string $stripeCustomerId = null, + /** + * Whether the Organization allows profiles outside of its managed domains. + * @deprecated + */ + public ?bool $allowProfilesOutsideOrganization = null, + ) { + } - public const RESOURCE_ATTRIBUTES = [ - "id", - "name", - "allowProfilesOutsideOrganization", - "domains", - "externalId", - "metadata" - ]; + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + name: $data['name'], + domains: array_map(fn ($item) => OrganizationDomain::fromArray($item), $data['domains']), + metadata: $data['metadata'], + externalId: $data['external_id'] ?? null, + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + stripeCustomerId: $data['stripe_customer_id'] ?? null, + allowProfilesOutsideOrganization: $data['allow_profiles_outside_organization'] ?? null, + ); + } - public const RESPONSE_TO_RESOURCE_KEY = [ - "id" => "id", - "name" => "name", - "allow_profiles_outside_organization" => "allowProfilesOutsideOrganization", - "domains" => "domains", - "external_id" => "externalId", - "metadata" => "metadata" - ]; + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'name' => $this->name, + 'domains' => array_map(fn ($item) => $item->toArray(), $this->domains), + 'metadata' => $this->metadata, + 'external_id' => $this->externalId, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'stripe_customer_id' => $this->stripeCustomerId, + 'allow_profiles_outside_organization' => $this->allowProfilesOutsideOrganization, + ]; + } } diff --git a/lib/Resource/OrganizationCreated.php b/lib/Resource/OrganizationCreated.php new file mode 100644 index 00000000..5a0d38ed --- /dev/null +++ b/lib/Resource/OrganizationCreated.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/OrganizationCreatedContext.php b/lib/Resource/OrganizationCreatedContext.php new file mode 100644 index 00000000..51d687c2 --- /dev/null +++ b/lib/Resource/OrganizationCreatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?OrganizationCreatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? OrganizationCreatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/OrganizationCreatedContextActor.php b/lib/Resource/OrganizationCreatedContextActor.php new file mode 100644 index 00000000..5f09caaa --- /dev/null +++ b/lib/Resource/OrganizationCreatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/OrganizationCreatedContextGoogleAnalyticsSession.php b/lib/Resource/OrganizationCreatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..a3b78bde --- /dev/null +++ b/lib/Resource/OrganizationCreatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/OrganizationCreatedData.php b/lib/Resource/OrganizationCreatedData.php new file mode 100644 index 00000000..c9b07780 --- /dev/null +++ b/lib/Resource/OrganizationCreatedData.php @@ -0,0 +1,71 @@ + + */ + public array $domains, + /** + * Object containing [metadata](https://workos.com/docs/authkit/metadata) key/value pairs associated with the Organization. + * @var array + */ + public array $metadata, + /** The external ID of the Organization. */ + public ?string $externalId, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + /** The Stripe customer ID of the Organization. */ + public ?string $stripeCustomerId = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + name: $data['name'], + domains: array_map(fn ($item) => OrganizationCreatedDataDomain::fromArray($item), $data['domains']), + metadata: $data['metadata'], + externalId: $data['external_id'] ?? null, + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + stripeCustomerId: $data['stripe_customer_id'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'name' => $this->name, + 'domains' => array_map(fn ($item) => $item->toArray(), $this->domains), + 'metadata' => $this->metadata, + 'external_id' => $this->externalId, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'stripe_customer_id' => $this->stripeCustomerId, + ]; + } +} diff --git a/lib/Resource/OrganizationCreatedDataDomain.php b/lib/Resource/OrganizationCreatedDataDomain.php new file mode 100644 index 00000000..63f96ec4 --- /dev/null +++ b/lib/Resource/OrganizationCreatedDataDomain.php @@ -0,0 +1,68 @@ + $this->object, + 'id' => $this->id, + 'organization_id' => $this->organizationId, + 'domain' => $this->domain, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'state' => $this->state?->value, + 'verification_prefix' => $this->verificationPrefix, + 'verification_token' => $this->verificationToken, + 'verification_strategy' => $this->verificationStrategy?->value, + ]; + } +} diff --git a/lib/Resource/OrganizationDeleted.php b/lib/Resource/OrganizationDeleted.php new file mode 100644 index 00000000..fca5fda3 --- /dev/null +++ b/lib/Resource/OrganizationDeleted.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/OrganizationDeletedContext.php b/lib/Resource/OrganizationDeletedContext.php new file mode 100644 index 00000000..af914d89 --- /dev/null +++ b/lib/Resource/OrganizationDeletedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?OrganizationDeletedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? OrganizationDeletedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/OrganizationDeletedContextActor.php b/lib/Resource/OrganizationDeletedContextActor.php new file mode 100644 index 00000000..97968d03 --- /dev/null +++ b/lib/Resource/OrganizationDeletedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/OrganizationDeletedContextGoogleAnalyticsSession.php b/lib/Resource/OrganizationDeletedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..06e31a9d --- /dev/null +++ b/lib/Resource/OrganizationDeletedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/OrganizationDeletedData.php b/lib/Resource/OrganizationDeletedData.php new file mode 100644 index 00000000..db14ef0e --- /dev/null +++ b/lib/Resource/OrganizationDeletedData.php @@ -0,0 +1,71 @@ + + */ + public array $domains, + /** + * Object containing [metadata](https://workos.com/docs/authkit/metadata) key/value pairs associated with the Organization. + * @var array + */ + public array $metadata, + /** The external ID of the Organization. */ + public ?string $externalId, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + /** The Stripe customer ID of the Organization. */ + public ?string $stripeCustomerId = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + name: $data['name'], + domains: array_map(fn ($item) => OrganizationDeletedDataDomain::fromArray($item), $data['domains']), + metadata: $data['metadata'], + externalId: $data['external_id'] ?? null, + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + stripeCustomerId: $data['stripe_customer_id'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'name' => $this->name, + 'domains' => array_map(fn ($item) => $item->toArray(), $this->domains), + 'metadata' => $this->metadata, + 'external_id' => $this->externalId, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'stripe_customer_id' => $this->stripeCustomerId, + ]; + } +} diff --git a/lib/Resource/OrganizationDeletedDataDomain.php b/lib/Resource/OrganizationDeletedDataDomain.php new file mode 100644 index 00000000..3564222a --- /dev/null +++ b/lib/Resource/OrganizationDeletedDataDomain.php @@ -0,0 +1,68 @@ + $this->object, + 'id' => $this->id, + 'organization_id' => $this->organizationId, + 'domain' => $this->domain, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'state' => $this->state?->value, + 'verification_prefix' => $this->verificationPrefix, + 'verification_token' => $this->verificationToken, + 'verification_strategy' => $this->verificationStrategy?->value, + ]; + } +} diff --git a/lib/Resource/OrganizationDomain.php b/lib/Resource/OrganizationDomain.php new file mode 100644 index 00000000..f15d7ff7 --- /dev/null +++ b/lib/Resource/OrganizationDomain.php @@ -0,0 +1,68 @@ + $this->object, + 'id' => $this->id, + 'organization_id' => $this->organizationId, + 'domain' => $this->domain, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'state' => $this->state?->value, + 'verification_prefix' => $this->verificationPrefix, + 'verification_token' => $this->verificationToken, + 'verification_strategy' => $this->verificationStrategy?->value, + ]; + } +} diff --git a/lib/Resource/OrganizationDomainCreated.php b/lib/Resource/OrganizationDomainCreated.php new file mode 100644 index 00000000..7f0c4cfe --- /dev/null +++ b/lib/Resource/OrganizationDomainCreated.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/OrganizationDomainCreatedContext.php b/lib/Resource/OrganizationDomainCreatedContext.php new file mode 100644 index 00000000..1207a8d8 --- /dev/null +++ b/lib/Resource/OrganizationDomainCreatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?OrganizationDomainCreatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? OrganizationDomainCreatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/OrganizationDomainCreatedContextActor.php b/lib/Resource/OrganizationDomainCreatedContextActor.php new file mode 100644 index 00000000..fdcb42b6 --- /dev/null +++ b/lib/Resource/OrganizationDomainCreatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/OrganizationDomainCreatedContextGoogleAnalyticsSession.php b/lib/Resource/OrganizationDomainCreatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..80d2d726 --- /dev/null +++ b/lib/Resource/OrganizationDomainCreatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/OrganizationDomainCreatedData.php b/lib/Resource/OrganizationDomainCreatedData.php new file mode 100644 index 00000000..858546e9 --- /dev/null +++ b/lib/Resource/OrganizationDomainCreatedData.php @@ -0,0 +1,69 @@ + $this->object, + 'id' => $this->id, + 'organization_id' => $this->organizationId, + 'domain' => $this->domain, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'state' => $this->state?->value, + 'verification_prefix' => $this->verificationPrefix, + 'verification_token' => $this->verificationToken, + 'verification_strategy' => $this->verificationStrategy?->value, + ]; + } +} diff --git a/lib/Resource/OrganizationDomainData.php b/lib/Resource/OrganizationDomainData.php new file mode 100644 index 00000000..0bd73ff8 --- /dev/null +++ b/lib/Resource/OrganizationDomainData.php @@ -0,0 +1,36 @@ + $this->domain, + 'state' => $this->state->value, + ]; + } +} diff --git a/lib/Resource/OrganizationDomainDataState.php b/lib/Resource/OrganizationDomainDataState.php new file mode 100644 index 00000000..8f2537c5 --- /dev/null +++ b/lib/Resource/OrganizationDomainDataState.php @@ -0,0 +1,13 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/OrganizationDomainDeletedContext.php b/lib/Resource/OrganizationDomainDeletedContext.php new file mode 100644 index 00000000..d534e14f --- /dev/null +++ b/lib/Resource/OrganizationDomainDeletedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?OrganizationDomainDeletedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? OrganizationDomainDeletedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/OrganizationDomainDeletedContextActor.php b/lib/Resource/OrganizationDomainDeletedContextActor.php new file mode 100644 index 00000000..06a95b40 --- /dev/null +++ b/lib/Resource/OrganizationDomainDeletedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/OrganizationDomainDeletedContextGoogleAnalyticsSession.php b/lib/Resource/OrganizationDomainDeletedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..19c9bd23 --- /dev/null +++ b/lib/Resource/OrganizationDomainDeletedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/OrganizationDomainDeletedData.php b/lib/Resource/OrganizationDomainDeletedData.php new file mode 100644 index 00000000..d6b8aebd --- /dev/null +++ b/lib/Resource/OrganizationDomainDeletedData.php @@ -0,0 +1,69 @@ + $this->object, + 'id' => $this->id, + 'organization_id' => $this->organizationId, + 'domain' => $this->domain, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'state' => $this->state?->value, + 'verification_prefix' => $this->verificationPrefix, + 'verification_token' => $this->verificationToken, + 'verification_strategy' => $this->verificationStrategy?->value, + ]; + } +} diff --git a/lib/Resource/OrganizationDomainStandAlone.php b/lib/Resource/OrganizationDomainStandAlone.php new file mode 100644 index 00000000..27ee65d9 --- /dev/null +++ b/lib/Resource/OrganizationDomainStandAlone.php @@ -0,0 +1,68 @@ + $this->object, + 'id' => $this->id, + 'organization_id' => $this->organizationId, + 'domain' => $this->domain, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'state' => $this->state?->value, + 'verification_prefix' => $this->verificationPrefix, + 'verification_token' => $this->verificationToken, + 'verification_strategy' => $this->verificationStrategy?->value, + ]; + } +} diff --git a/lib/Resource/OrganizationDomainStandAloneState.php b/lib/Resource/OrganizationDomainStandAloneState.php new file mode 100644 index 00000000..c9745298 --- /dev/null +++ b/lib/Resource/OrganizationDomainStandAloneState.php @@ -0,0 +1,16 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/OrganizationDomainUpdatedContext.php b/lib/Resource/OrganizationDomainUpdatedContext.php new file mode 100644 index 00000000..b16e369d --- /dev/null +++ b/lib/Resource/OrganizationDomainUpdatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?OrganizationDomainUpdatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? OrganizationDomainUpdatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/OrganizationDomainUpdatedContextActor.php b/lib/Resource/OrganizationDomainUpdatedContextActor.php new file mode 100644 index 00000000..3a8de648 --- /dev/null +++ b/lib/Resource/OrganizationDomainUpdatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/OrganizationDomainUpdatedContextGoogleAnalyticsSession.php b/lib/Resource/OrganizationDomainUpdatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..a2645f42 --- /dev/null +++ b/lib/Resource/OrganizationDomainUpdatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/OrganizationDomainUpdatedData.php b/lib/Resource/OrganizationDomainUpdatedData.php new file mode 100644 index 00000000..6c06ed01 --- /dev/null +++ b/lib/Resource/OrganizationDomainUpdatedData.php @@ -0,0 +1,69 @@ + $this->object, + 'id' => $this->id, + 'organization_id' => $this->organizationId, + 'domain' => $this->domain, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'state' => $this->state?->value, + 'verification_prefix' => $this->verificationPrefix, + 'verification_token' => $this->verificationToken, + 'verification_strategy' => $this->verificationStrategy?->value, + ]; + } +} diff --git a/lib/Resource/OrganizationDomainVerificationFailed.php b/lib/Resource/OrganizationDomainVerificationFailed.php new file mode 100644 index 00000000..3fd29d11 --- /dev/null +++ b/lib/Resource/OrganizationDomainVerificationFailed.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/OrganizationDomainVerificationFailedContext.php b/lib/Resource/OrganizationDomainVerificationFailedContext.php new file mode 100644 index 00000000..54f28cae --- /dev/null +++ b/lib/Resource/OrganizationDomainVerificationFailedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?OrganizationDomainVerificationFailedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? OrganizationDomainVerificationFailedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/OrganizationDomainVerificationFailedContextActor.php b/lib/Resource/OrganizationDomainVerificationFailedContextActor.php new file mode 100644 index 00000000..3aaa1b7d --- /dev/null +++ b/lib/Resource/OrganizationDomainVerificationFailedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/OrganizationDomainVerificationFailedContextGoogleAnalyticsSession.php b/lib/Resource/OrganizationDomainVerificationFailedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..9c849991 --- /dev/null +++ b/lib/Resource/OrganizationDomainVerificationFailedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/OrganizationDomainVerificationFailedData.php b/lib/Resource/OrganizationDomainVerificationFailedData.php new file mode 100644 index 00000000..fb15b0db --- /dev/null +++ b/lib/Resource/OrganizationDomainVerificationFailedData.php @@ -0,0 +1,37 @@ + $this->reason->value, + 'organization_domain' => $this->organizationDomain->toArray(), + ]; + } +} diff --git a/lib/Resource/OrganizationDomainVerificationFailedDataOrganizationDomain.php b/lib/Resource/OrganizationDomainVerificationFailedDataOrganizationDomain.php new file mode 100644 index 00000000..bcd558bc --- /dev/null +++ b/lib/Resource/OrganizationDomainVerificationFailedDataOrganizationDomain.php @@ -0,0 +1,69 @@ + $this->object, + 'id' => $this->id, + 'organization_id' => $this->organizationId, + 'domain' => $this->domain, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'state' => $this->state?->value, + 'verification_prefix' => $this->verificationPrefix, + 'verification_token' => $this->verificationToken, + 'verification_strategy' => $this->verificationStrategy?->value, + ]; + } +} diff --git a/lib/Resource/OrganizationDomainVerificationFailedDataReason.php b/lib/Resource/OrganizationDomainVerificationFailedDataReason.php new file mode 100644 index 00000000..f1c73690 --- /dev/null +++ b/lib/Resource/OrganizationDomainVerificationFailedDataReason.php @@ -0,0 +1,13 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/OrganizationDomainVerifiedContext.php b/lib/Resource/OrganizationDomainVerifiedContext.php new file mode 100644 index 00000000..dddad49c --- /dev/null +++ b/lib/Resource/OrganizationDomainVerifiedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?OrganizationDomainVerifiedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? OrganizationDomainVerifiedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/OrganizationDomainVerifiedContextActor.php b/lib/Resource/OrganizationDomainVerifiedContextActor.php new file mode 100644 index 00000000..1a1c2fe7 --- /dev/null +++ b/lib/Resource/OrganizationDomainVerifiedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/OrganizationDomainVerifiedContextGoogleAnalyticsSession.php b/lib/Resource/OrganizationDomainVerifiedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..89b9c63b --- /dev/null +++ b/lib/Resource/OrganizationDomainVerifiedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/OrganizationDomainVerifiedData.php b/lib/Resource/OrganizationDomainVerifiedData.php new file mode 100644 index 00000000..3848ed25 --- /dev/null +++ b/lib/Resource/OrganizationDomainVerifiedData.php @@ -0,0 +1,69 @@ + $this->object, + 'id' => $this->id, + 'organization_id' => $this->organizationId, + 'domain' => $this->domain, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'state' => $this->state?->value, + 'verification_prefix' => $this->verificationPrefix, + 'verification_token' => $this->verificationToken, + 'verification_strategy' => $this->verificationStrategy?->value, + ]; + } +} diff --git a/lib/Resource/OrganizationInput.php b/lib/Resource/OrganizationInput.php new file mode 100644 index 00000000..16c93a64 --- /dev/null +++ b/lib/Resource/OrganizationInput.php @@ -0,0 +1,61 @@ +|null + */ + public ?array $domains = null, + /** + * The domains associated with the organization, including verification state. + * @var array<\WorkOS\Resource\OrganizationDomainData>|null + */ + public ?array $domainData = null, + /** + * Object containing [metadata](https://workos.com/docs/authkit/metadata) key/value pairs associated with the Organization. + * @var array|null + */ + public ?array $metadata = null, + /** An external identifier for the Organization. */ + public ?string $externalId = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + name: $data['name'], + allowProfilesOutsideOrganization: $data['allow_profiles_outside_organization'] ?? null, + domains: $data['domains'] ?? null, + domainData: isset($data['domain_data']) ? array_map(fn ($item) => OrganizationDomainData::fromArray($item), $data['domain_data']) : null, + metadata: $data['metadata'] ?? null, + externalId: $data['external_id'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'name' => $this->name, + 'allow_profiles_outside_organization' => $this->allowProfilesOutsideOrganization, + 'domains' => $this->domains, + 'domain_data' => $this->domainData !== null ? array_map(fn ($item) => $item->toArray(), $this->domainData) : null, + 'metadata' => $this->metadata, + 'external_id' => $this->externalId, + ]; + } +} diff --git a/lib/Resource/OrganizationMembership.php b/lib/Resource/OrganizationMembership.php index 11cb048b..c5b5f27b 100644 --- a/lib/Resource/OrganizationMembership.php +++ b/lib/Resource/OrganizationMembership.php @@ -1,72 +1,75 @@ $roles - * @property 'active'|'inactive'|'pending' $status - * @property array $customAttributes - * @property bool $directoryManaged - * @property string $createdAt - * @property string $updatedAt - */ -class OrganizationMembership extends BaseWorkOSResource -{ - public const RESOURCE_TYPE = "organization_membership"; +namespace WorkOS\Resource; - public const RESOURCE_ATTRIBUTES = [ - "object", - "id", - "userId", - "organizationId", - "role", - "roles", - "status", - "customAttributes", - "directoryManaged", - "createdAt", - "updatedAt" - ]; +readonly class OrganizationMembership implements \JsonSerializable +{ + use JsonSerializableTrait; - public const RESPONSE_TO_RESOURCE_KEY = [ - "object" => "object", - "id" => "id", - "user_id" => "userId", - "organization_id" => "organizationId", - "role" => "role", - "roles" => "roles", - "status" => "status", - "custom_attributes" => "customAttributes", - "directory_managed" => "directoryManaged", - "created_at" => "createdAt", - "updated_at" => "updatedAt" - ]; + public function __construct( + /** Distinguishes the organization membership object. */ + public string $object, + /** The unique ID of the organization membership. */ + public string $id, + /** The ID of the user. */ + public string $userId, + /** The ID of the organization which the user belongs to. */ + public string $organizationId, + /** The status of the organization membership. One of `active`, `inactive`, or `pending`. */ + public OrganizationMembershipStatus $status, + /** Whether this organization membership is managed by a directory sync connection. */ + public bool $directoryManaged, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + /** The primary role assigned to the user within the organization. */ + public SlimRole $role, + /** The name of the organization which the user belongs to. */ + public ?string $organizationName = null, + /** + * An object containing IdP-sourced attributes from the linked [Directory User](https://workos.com/docs/reference/directory-sync/directory-user) or [SSO Profile](https://workos.com/docs/reference/sso/profile). Directory User attributes take precedence when both are linked. + * @var array|null + */ + public ?array $customAttributes = null, + ) { + } - public static function constructFromResponse($response) + public static function fromArray(array $data): self { - $instance = parent::constructFromResponse($response); - - if (isset($response["role"])) { - $instance->values["role"] = new RoleResponse($response["role"]["slug"]); - } - - if (isset($response["roles"])) { - $roles = []; - foreach ($response["roles"] as $role) { - $roles[] = new RoleResponse($role["slug"]); - } - $instance->values["roles"] = $roles; - } + return new self( + object: $data['object'], + id: $data['id'], + userId: $data['user_id'], + organizationId: $data['organization_id'], + status: OrganizationMembershipStatus::from($data['status']), + directoryManaged: $data['directory_managed'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + role: SlimRole::fromArray($data['role']), + organizationName: $data['organization_name'] ?? null, + customAttributes: $data['custom_attributes'] ?? null, + ); + } - return $instance; + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'user_id' => $this->userId, + 'organization_id' => $this->organizationId, + 'status' => $this->status->value, + 'directory_managed' => $this->directoryManaged, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'role' => $this->role->toArray(), + 'organization_name' => $this->organizationName, + 'custom_attributes' => $this->customAttributes, + ]; } } diff --git a/lib/Resource/OrganizationMembershipCreated.php b/lib/Resource/OrganizationMembershipCreated.php new file mode 100644 index 00000000..a202b537 --- /dev/null +++ b/lib/Resource/OrganizationMembershipCreated.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/OrganizationMembershipCreatedContext.php b/lib/Resource/OrganizationMembershipCreatedContext.php new file mode 100644 index 00000000..67878f24 --- /dev/null +++ b/lib/Resource/OrganizationMembershipCreatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?OrganizationMembershipCreatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? OrganizationMembershipCreatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/OrganizationMembershipCreatedContextActor.php b/lib/Resource/OrganizationMembershipCreatedContextActor.php new file mode 100644 index 00000000..aa590cf3 --- /dev/null +++ b/lib/Resource/OrganizationMembershipCreatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/OrganizationMembershipCreatedContextGoogleAnalyticsSession.php b/lib/Resource/OrganizationMembershipCreatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..3ef4b365 --- /dev/null +++ b/lib/Resource/OrganizationMembershipCreatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/OrganizationMembershipCreatedData.php b/lib/Resource/OrganizationMembershipCreatedData.php new file mode 100644 index 00000000..76f4a588 --- /dev/null +++ b/lib/Resource/OrganizationMembershipCreatedData.php @@ -0,0 +1,79 @@ + + */ + public array $customAttributes, + /** Whether the membership is managed by a directory sync provider. */ + public bool $directoryManaged, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + /** + * The roles associated with the membership. + * @var array<\WorkOS\Resource\SlimRole>|null + */ + public ?array $roles = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + userId: $data['user_id'], + organizationId: $data['organization_id'], + status: OrganizationMembershipStatus::from($data['status']), + role: SlimRole::fromArray($data['role']), + customAttributes: $data['custom_attributes'], + directoryManaged: $data['directory_managed'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + roles: isset($data['roles']) ? array_map(fn ($item) => SlimRole::fromArray($item), $data['roles']) : null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'user_id' => $this->userId, + 'organization_id' => $this->organizationId, + 'status' => $this->status->value, + 'role' => $this->role->toArray(), + 'custom_attributes' => $this->customAttributes, + 'directory_managed' => $this->directoryManaged, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'roles' => $this->roles !== null ? array_map(fn ($item) => $item->toArray(), $this->roles) : null, + ]; + } +} diff --git a/lib/Resource/OrganizationMembershipDeleted.php b/lib/Resource/OrganizationMembershipDeleted.php new file mode 100644 index 00000000..1f6f4078 --- /dev/null +++ b/lib/Resource/OrganizationMembershipDeleted.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/OrganizationMembershipDeletedContext.php b/lib/Resource/OrganizationMembershipDeletedContext.php new file mode 100644 index 00000000..472cd899 --- /dev/null +++ b/lib/Resource/OrganizationMembershipDeletedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?OrganizationMembershipDeletedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? OrganizationMembershipDeletedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/OrganizationMembershipDeletedContextActor.php b/lib/Resource/OrganizationMembershipDeletedContextActor.php new file mode 100644 index 00000000..e4ead175 --- /dev/null +++ b/lib/Resource/OrganizationMembershipDeletedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/OrganizationMembershipDeletedContextGoogleAnalyticsSession.php b/lib/Resource/OrganizationMembershipDeletedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..670793bf --- /dev/null +++ b/lib/Resource/OrganizationMembershipDeletedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/OrganizationMembershipDeletedData.php b/lib/Resource/OrganizationMembershipDeletedData.php new file mode 100644 index 00000000..7febcca1 --- /dev/null +++ b/lib/Resource/OrganizationMembershipDeletedData.php @@ -0,0 +1,79 @@ + + */ + public array $customAttributes, + /** Whether the membership is managed by a directory sync provider. */ + public bool $directoryManaged, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + /** + * The roles associated with the membership. + * @var array<\WorkOS\Resource\SlimRole>|null + */ + public ?array $roles = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + userId: $data['user_id'], + organizationId: $data['organization_id'], + status: OrganizationMembershipStatus::from($data['status']), + role: SlimRole::fromArray($data['role']), + customAttributes: $data['custom_attributes'], + directoryManaged: $data['directory_managed'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + roles: isset($data['roles']) ? array_map(fn ($item) => SlimRole::fromArray($item), $data['roles']) : null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'user_id' => $this->userId, + 'organization_id' => $this->organizationId, + 'status' => $this->status->value, + 'role' => $this->role->toArray(), + 'custom_attributes' => $this->customAttributes, + 'directory_managed' => $this->directoryManaged, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'roles' => $this->roles !== null ? array_map(fn ($item) => $item->toArray(), $this->roles) : null, + ]; + } +} diff --git a/lib/Resource/OrganizationMembershipStatus.php b/lib/Resource/OrganizationMembershipStatus.php new file mode 100644 index 00000000..3a5fe9b2 --- /dev/null +++ b/lib/Resource/OrganizationMembershipStatus.php @@ -0,0 +1,14 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/OrganizationMembershipUpdatedContext.php b/lib/Resource/OrganizationMembershipUpdatedContext.php new file mode 100644 index 00000000..6228c0dc --- /dev/null +++ b/lib/Resource/OrganizationMembershipUpdatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?OrganizationMembershipUpdatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? OrganizationMembershipUpdatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/OrganizationMembershipUpdatedContextActor.php b/lib/Resource/OrganizationMembershipUpdatedContextActor.php new file mode 100644 index 00000000..55efceee --- /dev/null +++ b/lib/Resource/OrganizationMembershipUpdatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/OrganizationMembershipUpdatedContextGoogleAnalyticsSession.php b/lib/Resource/OrganizationMembershipUpdatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..34bf9f05 --- /dev/null +++ b/lib/Resource/OrganizationMembershipUpdatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/OrganizationMembershipUpdatedData.php b/lib/Resource/OrganizationMembershipUpdatedData.php new file mode 100644 index 00000000..eb8f8a36 --- /dev/null +++ b/lib/Resource/OrganizationMembershipUpdatedData.php @@ -0,0 +1,79 @@ + + */ + public array $customAttributes, + /** Whether the membership is managed by a directory sync provider. */ + public bool $directoryManaged, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + /** + * The roles associated with the membership. + * @var array<\WorkOS\Resource\SlimRole>|null + */ + public ?array $roles = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + userId: $data['user_id'], + organizationId: $data['organization_id'], + status: OrganizationMembershipStatus::from($data['status']), + role: SlimRole::fromArray($data['role']), + customAttributes: $data['custom_attributes'], + directoryManaged: $data['directory_managed'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + roles: isset($data['roles']) ? array_map(fn ($item) => SlimRole::fromArray($item), $data['roles']) : null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'user_id' => $this->userId, + 'organization_id' => $this->organizationId, + 'status' => $this->status->value, + 'role' => $this->role->toArray(), + 'custom_attributes' => $this->customAttributes, + 'directory_managed' => $this->directoryManaged, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'roles' => $this->roles !== null ? array_map(fn ($item) => $item->toArray(), $this->roles) : null, + ]; + } +} diff --git a/lib/Resource/OrganizationRoleCreated.php b/lib/Resource/OrganizationRoleCreated.php new file mode 100644 index 00000000..042966be --- /dev/null +++ b/lib/Resource/OrganizationRoleCreated.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/OrganizationRoleCreatedContext.php b/lib/Resource/OrganizationRoleCreatedContext.php new file mode 100644 index 00000000..6e369b6e --- /dev/null +++ b/lib/Resource/OrganizationRoleCreatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?OrganizationRoleCreatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? OrganizationRoleCreatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/OrganizationRoleCreatedContextActor.php b/lib/Resource/OrganizationRoleCreatedContextActor.php new file mode 100644 index 00000000..37c31b7b --- /dev/null +++ b/lib/Resource/OrganizationRoleCreatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/OrganizationRoleCreatedContextGoogleAnalyticsSession.php b/lib/Resource/OrganizationRoleCreatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..68e51ce5 --- /dev/null +++ b/lib/Resource/OrganizationRoleCreatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/OrganizationRoleCreatedData.php b/lib/Resource/OrganizationRoleCreatedData.php new file mode 100644 index 00000000..487feaa5 --- /dev/null +++ b/lib/Resource/OrganizationRoleCreatedData.php @@ -0,0 +1,68 @@ + + */ + public array $permissions, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + organizationId: $data['organization_id'], + slug: $data['slug'], + name: $data['name'], + description: $data['description'] ?? null, + resourceTypeSlug: $data['resource_type_slug'], + permissions: $data['permissions'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'organization_id' => $this->organizationId, + 'slug' => $this->slug, + 'name' => $this->name, + 'description' => $this->description, + 'resource_type_slug' => $this->resourceTypeSlug, + 'permissions' => $this->permissions, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/OrganizationRoleDeleted.php b/lib/Resource/OrganizationRoleDeleted.php new file mode 100644 index 00000000..0d5c6fa4 --- /dev/null +++ b/lib/Resource/OrganizationRoleDeleted.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/OrganizationRoleDeletedContext.php b/lib/Resource/OrganizationRoleDeletedContext.php new file mode 100644 index 00000000..ff3920c4 --- /dev/null +++ b/lib/Resource/OrganizationRoleDeletedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?OrganizationRoleDeletedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? OrganizationRoleDeletedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/OrganizationRoleDeletedContextActor.php b/lib/Resource/OrganizationRoleDeletedContextActor.php new file mode 100644 index 00000000..67543e20 --- /dev/null +++ b/lib/Resource/OrganizationRoleDeletedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/OrganizationRoleDeletedContextGoogleAnalyticsSession.php b/lib/Resource/OrganizationRoleDeletedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..575b7e60 --- /dev/null +++ b/lib/Resource/OrganizationRoleDeletedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/OrganizationRoleDeletedData.php b/lib/Resource/OrganizationRoleDeletedData.php new file mode 100644 index 00000000..6b191224 --- /dev/null +++ b/lib/Resource/OrganizationRoleDeletedData.php @@ -0,0 +1,68 @@ + + */ + public array $permissions, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + organizationId: $data['organization_id'], + slug: $data['slug'], + name: $data['name'], + description: $data['description'] ?? null, + resourceTypeSlug: $data['resource_type_slug'], + permissions: $data['permissions'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'organization_id' => $this->organizationId, + 'slug' => $this->slug, + 'name' => $this->name, + 'description' => $this->description, + 'resource_type_slug' => $this->resourceTypeSlug, + 'permissions' => $this->permissions, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/OrganizationRoleUpdated.php b/lib/Resource/OrganizationRoleUpdated.php new file mode 100644 index 00000000..436ecaf8 --- /dev/null +++ b/lib/Resource/OrganizationRoleUpdated.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/OrganizationRoleUpdatedContext.php b/lib/Resource/OrganizationRoleUpdatedContext.php new file mode 100644 index 00000000..df5ea091 --- /dev/null +++ b/lib/Resource/OrganizationRoleUpdatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?OrganizationRoleUpdatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? OrganizationRoleUpdatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/OrganizationRoleUpdatedContextActor.php b/lib/Resource/OrganizationRoleUpdatedContextActor.php new file mode 100644 index 00000000..036e2104 --- /dev/null +++ b/lib/Resource/OrganizationRoleUpdatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/OrganizationRoleUpdatedContextGoogleAnalyticsSession.php b/lib/Resource/OrganizationRoleUpdatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..a876bf8c --- /dev/null +++ b/lib/Resource/OrganizationRoleUpdatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/OrganizationRoleUpdatedData.php b/lib/Resource/OrganizationRoleUpdatedData.php new file mode 100644 index 00000000..99f77f7b --- /dev/null +++ b/lib/Resource/OrganizationRoleUpdatedData.php @@ -0,0 +1,68 @@ + + */ + public array $permissions, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + organizationId: $data['organization_id'], + slug: $data['slug'], + name: $data['name'], + description: $data['description'] ?? null, + resourceTypeSlug: $data['resource_type_slug'], + permissions: $data['permissions'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'organization_id' => $this->organizationId, + 'slug' => $this->slug, + 'name' => $this->name, + 'description' => $this->description, + 'resource_type_slug' => $this->resourceTypeSlug, + 'permissions' => $this->permissions, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/OrganizationSelectionSessionAuthenticateRequest.php b/lib/Resource/OrganizationSelectionSessionAuthenticateRequest.php new file mode 100644 index 00000000..a5bc145f --- /dev/null +++ b/lib/Resource/OrganizationSelectionSessionAuthenticateRequest.php @@ -0,0 +1,59 @@ + $this->clientId, + 'client_secret' => $this->clientSecret, + 'grant_type' => $this->grantType, + 'pending_authentication_token' => $this->pendingAuthenticationToken, + 'organization_id' => $this->organizationId, + 'ip_address' => $this->ipAddress, + 'device_id' => $this->deviceId, + 'user_agent' => $this->userAgent, + ]; + } +} diff --git a/lib/Resource/OrganizationUpdated.php b/lib/Resource/OrganizationUpdated.php new file mode 100644 index 00000000..7d361834 --- /dev/null +++ b/lib/Resource/OrganizationUpdated.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/OrganizationUpdatedContext.php b/lib/Resource/OrganizationUpdatedContext.php new file mode 100644 index 00000000..f35aee50 --- /dev/null +++ b/lib/Resource/OrganizationUpdatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?OrganizationUpdatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? OrganizationUpdatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/OrganizationUpdatedContextActor.php b/lib/Resource/OrganizationUpdatedContextActor.php new file mode 100644 index 00000000..78e45657 --- /dev/null +++ b/lib/Resource/OrganizationUpdatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/OrganizationUpdatedContextGoogleAnalyticsSession.php b/lib/Resource/OrganizationUpdatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..28c60308 --- /dev/null +++ b/lib/Resource/OrganizationUpdatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/OrganizationUpdatedData.php b/lib/Resource/OrganizationUpdatedData.php new file mode 100644 index 00000000..7166101c --- /dev/null +++ b/lib/Resource/OrganizationUpdatedData.php @@ -0,0 +1,71 @@ + + */ + public array $domains, + /** + * Object containing [metadata](https://workos.com/docs/authkit/metadata) key/value pairs associated with the Organization. + * @var array + */ + public array $metadata, + /** The external ID of the Organization. */ + public ?string $externalId, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + /** The Stripe customer ID of the Organization. */ + public ?string $stripeCustomerId = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + name: $data['name'], + domains: array_map(fn ($item) => OrganizationUpdatedDataDomain::fromArray($item), $data['domains']), + metadata: $data['metadata'], + externalId: $data['external_id'] ?? null, + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + stripeCustomerId: $data['stripe_customer_id'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'name' => $this->name, + 'domains' => array_map(fn ($item) => $item->toArray(), $this->domains), + 'metadata' => $this->metadata, + 'external_id' => $this->externalId, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'stripe_customer_id' => $this->stripeCustomerId, + ]; + } +} diff --git a/lib/Resource/OrganizationUpdatedDataDomain.php b/lib/Resource/OrganizationUpdatedDataDomain.php new file mode 100644 index 00000000..cc4fbc16 --- /dev/null +++ b/lib/Resource/OrganizationUpdatedDataDomain.php @@ -0,0 +1,68 @@ + $this->object, + 'id' => $this->id, + 'organization_id' => $this->organizationId, + 'domain' => $this->domain, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'state' => $this->state?->value, + 'verification_prefix' => $this->verificationPrefix, + 'verification_token' => $this->verificationToken, + 'verification_strategy' => $this->verificationStrategy?->value, + ]; + } +} diff --git a/lib/Resource/OrganizationsApiKeysOrder.php b/lib/Resource/OrganizationsApiKeysOrder.php new file mode 100644 index 00000000..db6b6c49 --- /dev/null +++ b/lib/Resource/OrganizationsApiKeysOrder.php @@ -0,0 +1,14 @@ + $users, "after" => $after] = $result - * 3. Fluent property access: $result->users, $result->after, $result->before - * - * This class standardizes pagination across all WorkOS resources while maintaining - * backwards compatibility with existing code. - */ -class PaginatedResource implements \ArrayAccess, \IteratorAggregate, \Countable -{ - /** - * @var ?string Before cursor for pagination - */ - private $before; - - /** - * @var ?string After cursor for pagination - */ - private $after; - - /** - * @var array The paginated data items - */ - private $data; - - /** - * @var string The key name for the data array (e.g., 'users', 'directories') - */ - private $dataKey; - - /** - * PaginatedResource constructor. - * - * @param ?string $before Before cursor - * @param ?string $after After cursor - * @param array $data Array of resource objects - * @param string $dataKey The key name for accessing the data - */ - public function __construct(?string $before, ?string $after, array $data, string $dataKey) - { - if (in_array($dataKey, ['before', 'after', 'data'], true)) { - throw new \InvalidArgumentException("dataKey '$dataKey' conflicts with reserved keys"); - } - - $this->before = $before; - $this->after = $after; - $this->data = $data; - $this->dataKey = $dataKey; - } - - /** - * Construct a PaginatedResource from an API response - * - * @param array $response The API response containing 'data', 'list_metadata', etc. - * @param string $resourceClass The fully qualified class name of the resource type - * @param string $dataKey The key name for the data array (e.g., 'users', 'directories') - * @return self - */ - public static function constructFromResponse(array $response, string $resourceClass, string $dataKey): self - { - $data = []; - list($before, $after) = \WorkOS\Util\Request::parsePaginationArgs($response); - - foreach ($response["data"] as $responseData) { - \array_push($data, $resourceClass::constructFromResponse($responseData)); - } - - return new self($before, $after, $data, $dataKey); - } - - /** - * Magic getter for fluent property access - * - * @param string $name Property name - * @return mixed - */ - public function __get(string $name) - { - if ($name === 'before') { - return $this->before; - } - - if ($name === 'after') { - return $this->after; - } - - if ($name === 'data' || $name === $this->dataKey) { - return $this->data; - } - - return null; - } - - /** - * ArrayAccess: Check if offset exists - * - * @param mixed $offset - * @return bool - */ - #[\ReturnTypeWillChange] - public function offsetExists($offset): bool - { - // Support numeric indices for bare destructuring - if (is_int($offset)) { - return $offset >= 0 && $offset <= 2; - } - - // Support named keys for named destructuring - return in_array($offset, ['before', 'after', 'data', $this->dataKey], true); - } - - /** - * ArrayAccess: Get value at offset - * - * @param mixed $offset - * @return mixed - */ - #[\ReturnTypeWillChange] - public function offsetGet($offset) - { - // Support numeric indices for bare destructuring: [0 => before, 1 => after, 2 => data] - if ($offset === 0) { - return $this->before; - } - - if ($offset === 1) { - return $this->after; - } - - if ($offset === 2) { - return $this->data; - } - - // Support named keys for named destructuring - if ($offset === 'before') { - return $this->before; - } - - if ($offset === 'after') { - return $this->after; - } - - if ($offset === 'data' || $offset === $this->dataKey) { - return $this->data; - } - - return null; - } - - /** - * ArrayAccess: Set value at offset (not supported) - * - * @param mixed $offset - * @param mixed $value - * @return void - */ - #[\ReturnTypeWillChange] - public function offsetSet($offset, $value): void - { - throw new \BadMethodCallException('PaginatedResource is immutable'); - } - - /** - * ArrayAccess: Unset offset (not supported) - * - * @param mixed $offset - * @return void - */ - #[\ReturnTypeWillChange] - public function offsetUnset($offset): void - { - throw new \BadMethodCallException('PaginatedResource is immutable'); - } - - /** - * IteratorAggregate: Get iterator for the data array - * - * @return \ArrayIterator - */ - public function getIterator(): \Traversable - { - return new \ArrayIterator($this->data); - } - - /** - * Magic isset for property checking - * - * @param string $name - * @return bool - */ - public function __isset(string $name): bool - { - if ($name === 'before') { - return $this->before !== null; - } - - if ($name === 'after') { - return $this->after !== null; - } - - if ($name === 'data' || $name === $this->dataKey) { - return true; - } - - return false; - } - - /** - * Countable: Get the number of data items - * - * @return int - */ - public function count(): int - { - return count($this->data); - } -} diff --git a/lib/Resource/PasswordReset.php b/lib/Resource/PasswordReset.php index 147d6703..5173223f 100644 --- a/lib/Resource/PasswordReset.php +++ b/lib/Resource/PasswordReset.php @@ -1,34 +1,60 @@ "object", - "id" => "id", - "user_id" => "userId", - "email" => "email", - "password_reset_token" => "passwordResetToken", - "password_reset_url" => "passwordResetUrl", - "expires_at" => "expiresAt", - "created_at" => "createdAt", - ]; + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'user_id' => $this->userId, + 'email' => $this->email, + 'expires_at' => $this->expiresAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'password_reset_token' => $this->passwordResetToken, + 'password_reset_url' => $this->passwordResetUrl, + ]; + } } diff --git a/lib/Resource/PasswordResetCreated.php b/lib/Resource/PasswordResetCreated.php new file mode 100644 index 00000000..0ef7a43d --- /dev/null +++ b/lib/Resource/PasswordResetCreated.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/PasswordResetCreatedContext.php b/lib/Resource/PasswordResetCreatedContext.php new file mode 100644 index 00000000..f486e1ec --- /dev/null +++ b/lib/Resource/PasswordResetCreatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?PasswordResetCreatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? PasswordResetCreatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/PasswordResetCreatedContextActor.php b/lib/Resource/PasswordResetCreatedContextActor.php new file mode 100644 index 00000000..52227c5f --- /dev/null +++ b/lib/Resource/PasswordResetCreatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/PasswordResetCreatedContextGoogleAnalyticsSession.php b/lib/Resource/PasswordResetCreatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..c1a098d5 --- /dev/null +++ b/lib/Resource/PasswordResetCreatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/PasswordResetCreatedData.php b/lib/Resource/PasswordResetCreatedData.php new file mode 100644 index 00000000..f24ec2f2 --- /dev/null +++ b/lib/Resource/PasswordResetCreatedData.php @@ -0,0 +1,53 @@ + $this->object, + 'id' => $this->id, + 'user_id' => $this->userId, + 'email' => $this->email, + 'expires_at' => $this->expiresAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/PasswordResetSucceeded.php b/lib/Resource/PasswordResetSucceeded.php new file mode 100644 index 00000000..38d906fa --- /dev/null +++ b/lib/Resource/PasswordResetSucceeded.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/PasswordResetSucceededContext.php b/lib/Resource/PasswordResetSucceededContext.php new file mode 100644 index 00000000..6bda9c0b --- /dev/null +++ b/lib/Resource/PasswordResetSucceededContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?PasswordResetSucceededContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? PasswordResetSucceededContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/PasswordResetSucceededContextActor.php b/lib/Resource/PasswordResetSucceededContextActor.php new file mode 100644 index 00000000..cb7f753f --- /dev/null +++ b/lib/Resource/PasswordResetSucceededContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/PasswordResetSucceededContextGoogleAnalyticsSession.php b/lib/Resource/PasswordResetSucceededContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..d57e5f2a --- /dev/null +++ b/lib/Resource/PasswordResetSucceededContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/PasswordResetSucceededData.php b/lib/Resource/PasswordResetSucceededData.php new file mode 100644 index 00000000..a945ff88 --- /dev/null +++ b/lib/Resource/PasswordResetSucceededData.php @@ -0,0 +1,53 @@ + $this->object, + 'id' => $this->id, + 'user_id' => $this->userId, + 'email' => $this->email, + 'expires_at' => $this->expiresAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/PasswordSessionAuthenticateRequest.php b/lib/Resource/PasswordSessionAuthenticateRequest.php new file mode 100644 index 00000000..5be9c025 --- /dev/null +++ b/lib/Resource/PasswordSessionAuthenticateRequest.php @@ -0,0 +1,63 @@ + $this->clientId, + 'client_secret' => $this->clientSecret, + 'grant_type' => $this->grantType, + 'email' => $this->email, + 'password' => $this->password, + 'invitation_token' => $this->invitationToken, + 'ip_address' => $this->ipAddress, + 'device_id' => $this->deviceId, + 'user_agent' => $this->userAgent, + ]; + } +} diff --git a/lib/Resource/PasswordlessSession.php b/lib/Resource/PasswordlessSession.php deleted file mode 100644 index 890150d5..00000000 --- a/lib/Resource/PasswordlessSession.php +++ /dev/null @@ -1,27 +0,0 @@ - "id", - "email" => "email", - "expires_at" => "expiresAt", - "link" => "link", - "object" => "object" - ]; -} diff --git a/lib/Resource/Permission.php b/lib/Resource/Permission.php index 9083096c..23e6a314 100644 --- a/lib/Resource/Permission.php +++ b/lib/Resource/Permission.php @@ -1,43 +1,64 @@ "id", - "slug" => "slug", - "name" => "name", - "description" => "description", - "resource_type_slug" => "resource_type_slug", - "system" => "system", - "created_at" => "created_at", - "updated_at" => "updated_at" - ]; + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'slug' => $this->slug, + 'name' => $this->name, + 'description' => $this->description, + 'system' => $this->system, + 'resource_type_slug' => $this->resourceTypeSlug, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } } diff --git a/lib/Resource/PermissionCreated.php b/lib/Resource/PermissionCreated.php new file mode 100644 index 00000000..dd694c4d --- /dev/null +++ b/lib/Resource/PermissionCreated.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/PermissionCreatedContext.php b/lib/Resource/PermissionCreatedContext.php new file mode 100644 index 00000000..69500fb8 --- /dev/null +++ b/lib/Resource/PermissionCreatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?PermissionCreatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? PermissionCreatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/PermissionCreatedContextActor.php b/lib/Resource/PermissionCreatedContextActor.php new file mode 100644 index 00000000..47a6b235 --- /dev/null +++ b/lib/Resource/PermissionCreatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/PermissionCreatedContextGoogleAnalyticsSession.php b/lib/Resource/PermissionCreatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..c2efb9d3 --- /dev/null +++ b/lib/Resource/PermissionCreatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/PermissionCreatedData.php b/lib/Resource/PermissionCreatedData.php new file mode 100644 index 00000000..42cf7086 --- /dev/null +++ b/lib/Resource/PermissionCreatedData.php @@ -0,0 +1,61 @@ + $this->object, + 'id' => $this->id, + 'slug' => $this->slug, + 'name' => $this->name, + 'description' => $this->description, + 'system' => $this->system, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/PermissionDeleted.php b/lib/Resource/PermissionDeleted.php new file mode 100644 index 00000000..f90cc1de --- /dev/null +++ b/lib/Resource/PermissionDeleted.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/PermissionDeletedContext.php b/lib/Resource/PermissionDeletedContext.php new file mode 100644 index 00000000..a7669dd3 --- /dev/null +++ b/lib/Resource/PermissionDeletedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?PermissionDeletedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? PermissionDeletedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/PermissionDeletedContextActor.php b/lib/Resource/PermissionDeletedContextActor.php new file mode 100644 index 00000000..2e240be0 --- /dev/null +++ b/lib/Resource/PermissionDeletedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/PermissionDeletedContextGoogleAnalyticsSession.php b/lib/Resource/PermissionDeletedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..f3105833 --- /dev/null +++ b/lib/Resource/PermissionDeletedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/PermissionDeletedData.php b/lib/Resource/PermissionDeletedData.php new file mode 100644 index 00000000..7686c62d --- /dev/null +++ b/lib/Resource/PermissionDeletedData.php @@ -0,0 +1,61 @@ + $this->object, + 'id' => $this->id, + 'slug' => $this->slug, + 'name' => $this->name, + 'description' => $this->description, + 'system' => $this->system, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/PermissionUpdated.php b/lib/Resource/PermissionUpdated.php new file mode 100644 index 00000000..fe3449a2 --- /dev/null +++ b/lib/Resource/PermissionUpdated.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/PermissionUpdatedContext.php b/lib/Resource/PermissionUpdatedContext.php new file mode 100644 index 00000000..4f4cc094 --- /dev/null +++ b/lib/Resource/PermissionUpdatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?PermissionUpdatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? PermissionUpdatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/PermissionUpdatedContextActor.php b/lib/Resource/PermissionUpdatedContextActor.php new file mode 100644 index 00000000..abd60928 --- /dev/null +++ b/lib/Resource/PermissionUpdatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/PermissionUpdatedContextGoogleAnalyticsSession.php b/lib/Resource/PermissionUpdatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..409ba4d1 --- /dev/null +++ b/lib/Resource/PermissionUpdatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/PermissionUpdatedData.php b/lib/Resource/PermissionUpdatedData.php new file mode 100644 index 00000000..87bdfd2e --- /dev/null +++ b/lib/Resource/PermissionUpdatedData.php @@ -0,0 +1,61 @@ + $this->object, + 'id' => $this->id, + 'slug' => $this->slug, + 'name' => $this->name, + 'description' => $this->description, + 'system' => $this->system, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/PermissionsOrder.php b/lib/Resource/PermissionsOrder.php new file mode 100644 index 00000000..27ff6c0a --- /dev/null +++ b/lib/Resource/PermissionsOrder.php @@ -0,0 +1,14 @@ + "link" - ]; -} diff --git a/lib/Resource/PortalLinkResponse.php b/lib/Resource/PortalLinkResponse.php new file mode 100644 index 00000000..31e3247c --- /dev/null +++ b/lib/Resource/PortalLinkResponse.php @@ -0,0 +1,32 @@ + $this->link, + ]; + } +} diff --git a/lib/Resource/Profile.php b/lib/Resource/Profile.php index 2d455a9f..7ba390fe 100644 --- a/lib/Resource/Profile.php +++ b/lib/Resource/Profile.php @@ -1,77 +1,96 @@ |null $roles - * @property array $groups - * @property array $rawAttributes - */ -class Profile extends BaseWorkOSResource -{ - public const RESOURCE_TYPE = "profile"; +namespace WorkOS\Resource; - public const RESOURCE_ATTRIBUTES = [ - "id", - "email", - "firstName", - "lastName", - "organizationId", - "connectionId", - "connectionType", - "idpId", - "role", - "roles", - "groups", - "customAttributes", - "rawAttributes" - ]; +readonly class Profile implements \JsonSerializable +{ + use JsonSerializableTrait; - public const RESPONSE_TO_RESOURCE_KEY = [ - "id" => "id", - "email" => "email", - "first_name" => "firstName", - "last_name" => "lastName", - "organization_id" => "organizationId", - "connection_id" => "connectionId", - "connection_type" => "connectionType", - "idp_id" => "idpId", - "role" => "role", - "roles" => "roles", - "groups" => "groups", - "custom_attributes" => "customAttributes", - "raw_attributes" => "rawAttributes" - ]; + public function __construct( + /** Distinguishes the profile object. */ + public string $object, + /** Unique identifier of the profile. */ + public string $id, + /** The ID of the organization the user belongs to. */ + public ?string $organizationId, + /** The ID of the SSO connection used for authentication. */ + public string $connectionId, + /** The type of SSO connection. */ + public ConnectionType $connectionType, + /** The user's unique identifier from the identity provider. */ + public string $idpId, + /** The user's email address. */ + public string $email, + /** The user's first name. */ + public ?string $firstName, + /** The user's last name. */ + public ?string $lastName, + /** + * The complete set of raw attributes returned by the identity provider. + * @var array + */ + public array $rawAttributes, + /** The role assigned to the user within the organization, if applicable. */ + public ?SlimRole $role = null, + /** + * The roles assigned to the user within the organization, if applicable. + * @var array<\WorkOS\Resource\SlimRole>|null + */ + public ?array $roles = null, + /** + * The groups the user belongs to, as returned by the identity provider. + * @var array|null + */ + public ?array $groups = null, + /** + * Custom attribute mappings defined for the connection, returned as key-value pairs. + * @var array|null + */ + public ?array $customAttributes = null, + ) { + } - public static function constructFromResponse($response) + public static function fromArray(array $data): self { - $instance = parent::constructFromResponse($response); - - if (isset($response["role"])) { - $instance->values["role"] = new RoleResponse($response["role"]["slug"]); - } - - if (isset($response["roles"])) { - $roles = []; - foreach ($response["roles"] as $role) { - $roles[] = new RoleResponse($role["slug"]); - } - $instance->values["roles"] = $roles; - } + return new self( + object: $data['object'], + id: $data['id'], + organizationId: $data['organization_id'] ?? null, + connectionId: $data['connection_id'], + connectionType: ConnectionType::from($data['connection_type']), + idpId: $data['idp_id'], + email: $data['email'], + firstName: $data['first_name'] ?? null, + lastName: $data['last_name'] ?? null, + rawAttributes: $data['raw_attributes'], + role: isset($data['role']) ? SlimRole::fromArray($data['role']) : null, + roles: isset($data['roles']) ? array_map(fn ($item) => SlimRole::fromArray($item), $data['roles']) : null, + groups: $data['groups'] ?? null, + customAttributes: $data['custom_attributes'] ?? null, + ); + } - return $instance; + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'organization_id' => $this->organizationId, + 'connection_id' => $this->connectionId, + 'connection_type' => $this->connectionType->value, + 'idp_id' => $this->idpId, + 'email' => $this->email, + 'first_name' => $this->firstName, + 'last_name' => $this->lastName, + 'raw_attributes' => $this->rawAttributes, + 'role' => $this->role?->toArray(), + 'roles' => $this->roles !== null ? array_map(fn ($item) => $item->toArray(), $this->roles) : null, + 'groups' => $this->groups, + 'custom_attributes' => $this->customAttributes, + ]; } } diff --git a/lib/Resource/ProfileAndToken.php b/lib/Resource/ProfileAndToken.php deleted file mode 100644 index 96cb5e4c..00000000 --- a/lib/Resource/ProfileAndToken.php +++ /dev/null @@ -1,30 +0,0 @@ - "accessToken" - ]; - - public static function constructFromResponse($response) - { - $instance = parent::constructFromResponse($response); - - $instance->values["profile"] = Profile::constructFromResponse($response["profile"]); - - return $instance; - } -} diff --git a/lib/Resource/ProfileConnectionType.php b/lib/Resource/ProfileConnectionType.php new file mode 100644 index 00000000..982d459b --- /dev/null +++ b/lib/Resource/ProfileConnectionType.php @@ -0,0 +1,62 @@ + $this->message, + ]; + } +} diff --git a/lib/Resource/RadarStandaloneAssessRequest.php b/lib/Resource/RadarStandaloneAssessRequest.php new file mode 100644 index 00000000..893d580d --- /dev/null +++ b/lib/Resource/RadarStandaloneAssessRequest.php @@ -0,0 +1,56 @@ + $this->ipAddress, + 'user_agent' => $this->userAgent, + 'email' => $this->email, + 'auth_method' => $this->authMethod->value, + 'action' => $this->action->value, + 'device_fingerprint' => $this->deviceFingerprint, + 'bot_score' => $this->botScore, + ]; + } +} diff --git a/lib/Resource/RadarStandaloneAssessRequestAction.php b/lib/Resource/RadarStandaloneAssessRequestAction.php new file mode 100644 index 00000000..a85557c6 --- /dev/null +++ b/lib/Resource/RadarStandaloneAssessRequestAction.php @@ -0,0 +1,19 @@ + $this->entry, + ]; + } +} diff --git a/lib/Resource/RadarStandaloneResponse.php b/lib/Resource/RadarStandaloneResponse.php new file mode 100644 index 00000000..c0afcab3 --- /dev/null +++ b/lib/Resource/RadarStandaloneResponse.php @@ -0,0 +1,48 @@ + $this->verdict->value, + 'reason' => $this->reason, + 'attempt_id' => $this->attemptId, + 'control' => $this->control?->value, + 'blocklist_type' => $this->blocklistType?->value, + ]; + } +} diff --git a/lib/Resource/RadarStandaloneResponseBlocklistType.php b/lib/Resource/RadarStandaloneResponseBlocklistType.php new file mode 100644 index 00000000..d09f1212 --- /dev/null +++ b/lib/Resource/RadarStandaloneResponseBlocklistType.php @@ -0,0 +1,18 @@ + $this->challengeStatus, + 'attempt_status' => $this->attemptStatus, + ]; + } +} diff --git a/lib/Resource/RadarStandaloneUpdateRadarListRequest.php b/lib/Resource/RadarStandaloneUpdateRadarListRequest.php new file mode 100644 index 00000000..97d24653 --- /dev/null +++ b/lib/Resource/RadarStandaloneUpdateRadarListRequest.php @@ -0,0 +1,32 @@ + $this->entry, + ]; + } +} diff --git a/lib/Resource/RadarType.php b/lib/Resource/RadarType.php new file mode 100644 index 00000000..1dbe2290 --- /dev/null +++ b/lib/Resource/RadarType.php @@ -0,0 +1,18 @@ + $this->object, + 'id' => $this->id, + 'uri' => $this->uri, + 'default' => $this->default, + 'created_at' => $this->createdAt, + 'updated_at' => $this->updatedAt, + ]; + } +} diff --git a/lib/Resource/RedirectUriInput.php b/lib/Resource/RedirectUriInput.php new file mode 100644 index 00000000..3b8a73ca --- /dev/null +++ b/lib/Resource/RedirectUriInput.php @@ -0,0 +1,36 @@ + $this->uri, + 'default' => $this->default, + ]; + } +} diff --git a/lib/Resource/RefreshTokenSessionAuthenticateRequest.php b/lib/Resource/RefreshTokenSessionAuthenticateRequest.php new file mode 100644 index 00000000..e7d174c0 --- /dev/null +++ b/lib/Resource/RefreshTokenSessionAuthenticateRequest.php @@ -0,0 +1,59 @@ + $this->clientId, + 'client_secret' => $this->clientSecret, + 'grant_type' => $this->grantType, + 'refresh_token' => $this->refreshToken, + 'organization_id' => $this->organizationId, + 'ip_address' => $this->ipAddress, + 'device_id' => $this->deviceId, + 'user_agent' => $this->userAgent, + ]; + } +} diff --git a/lib/Resource/RemoveRole.php b/lib/Resource/RemoveRole.php new file mode 100644 index 00000000..740c6f90 --- /dev/null +++ b/lib/Resource/RemoveRole.php @@ -0,0 +1,44 @@ + $this->roleSlug, + 'resource_id' => $this->resourceId, + 'resource_external_id' => $this->resourceExternalId, + 'resource_type_slug' => $this->resourceTypeSlug, + ]; + } +} diff --git a/lib/Resource/ResendUserInviteOptions.php b/lib/Resource/ResendUserInviteOptions.php new file mode 100644 index 00000000..5330e7ba --- /dev/null +++ b/lib/Resource/ResendUserInviteOptions.php @@ -0,0 +1,32 @@ + $this->locale?->value, + ]; + } +} diff --git a/lib/Resource/ResendUserInviteOptionsLocale.php b/lib/Resource/ResendUserInviteOptionsLocale.php new file mode 100644 index 00000000..1ab88a70 --- /dev/null +++ b/lib/Resource/ResendUserInviteOptionsLocale.php @@ -0,0 +1,101 @@ + $this->user->toArray(), + ]; + } +} diff --git a/lib/Resource/Response.php b/lib/Resource/Response.php deleted file mode 100644 index ec411de6..00000000 --- a/lib/Resource/Response.php +++ /dev/null @@ -1,47 +0,0 @@ -body = $body; - $this->headers = $headers; - $this->statusCode = $statusCode; - } - - public function json() - { - if (!isset($json)) { - $this->json = \json_decode($this->body, true); - } - - return $this->json; - } -} diff --git a/lib/Resource/RevokeSession.php b/lib/Resource/RevokeSession.php new file mode 100644 index 00000000..f016b102 --- /dev/null +++ b/lib/Resource/RevokeSession.php @@ -0,0 +1,36 @@ + $this->sessionId, + 'return_to' => $this->returnTo, + ]; + } +} diff --git a/lib/Resource/Role.php b/lib/Resource/Role.php index 7e0a2fe9..f5303186 100644 --- a/lib/Resource/Role.php +++ b/lib/Resource/Role.php @@ -1,46 +1,71 @@ $permissions - * @property string $resource_type_slug - * @property string $type - * @property string $created_at - * @property string $updated_at - */ +namespace WorkOS\Resource; -class Role extends BaseWorkOSResource +readonly class Role implements \JsonSerializable { - public const RESOURCE_TYPE = "role"; + use JsonSerializableTrait; + + public function __construct( + /** A unique slug for the role. */ + public string $slug, + /** Distinguishes the role object. */ + public string $object, + /** Unique identifier of the role. */ + public string $id, + /** A descriptive name for the role. */ + public string $name, + /** An optional description of the role. */ + public ?string $description, + /** Whether the role is scoped to the environment or an organization. */ + public RoleType $type, + /** The slug of the resource type the role is scoped to. */ + public string $resourceTypeSlug, + /** + * The permission slugs assigned to the role. + * @var array + */ + public array $permissions, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + ) { + } - public const RESOURCE_ATTRIBUTES = [ - "id", - "name", - "slug", - "description", - "permissions", - "resource_type_slug", - "type", - "created_at", - "updated_at" - ]; + public static function fromArray(array $data): self + { + return new self( + slug: $data['slug'], + object: $data['object'], + id: $data['id'], + name: $data['name'], + description: $data['description'] ?? null, + type: RoleType::from($data['type']), + resourceTypeSlug: $data['resource_type_slug'], + permissions: $data['permissions'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + ); + } - public const RESPONSE_TO_RESOURCE_KEY = [ - "id" => "id", - "name" => "name", - "slug" => "slug", - "description" => "description", - "permissions" => "permissions", - "resource_type_slug" => "resource_type_slug", - "type" => "type", - "created_at" => "created_at", - "updated_at" => "updated_at" - ]; + public function toArray(): array + { + return [ + 'slug' => $this->slug, + 'object' => $this->object, + 'id' => $this->id, + 'name' => $this->name, + 'description' => $this->description, + 'type' => $this->type->value, + 'resource_type_slug' => $this->resourceTypeSlug, + 'permissions' => $this->permissions, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } } diff --git a/lib/Resource/RoleAssignment.php b/lib/Resource/RoleAssignment.php new file mode 100644 index 00000000..23190cd8 --- /dev/null +++ b/lib/Resource/RoleAssignment.php @@ -0,0 +1,52 @@ + $this->object, + 'id' => $this->id, + 'role' => $this->role->toArray(), + 'resource' => $this->resource->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/RoleAssignmentResource.php b/lib/Resource/RoleAssignmentResource.php new file mode 100644 index 00000000..21fc5faa --- /dev/null +++ b/lib/Resource/RoleAssignmentResource.php @@ -0,0 +1,41 @@ + $this->id, + 'external_id' => $this->externalId, + 'resource_type_slug' => $this->resourceTypeSlug, + ]; + } +} diff --git a/lib/Resource/RoleCreated.php b/lib/Resource/RoleCreated.php new file mode 100644 index 00000000..e81d6d00 --- /dev/null +++ b/lib/Resource/RoleCreated.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/RoleCreatedContext.php b/lib/Resource/RoleCreatedContext.php new file mode 100644 index 00000000..a8672d84 --- /dev/null +++ b/lib/Resource/RoleCreatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?RoleCreatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? RoleCreatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/RoleCreatedContextActor.php b/lib/Resource/RoleCreatedContextActor.php new file mode 100644 index 00000000..7c922ea2 --- /dev/null +++ b/lib/Resource/RoleCreatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/RoleCreatedContextGoogleAnalyticsSession.php b/lib/Resource/RoleCreatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..9c1b6f37 --- /dev/null +++ b/lib/Resource/RoleCreatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/RoleCreatedData.php b/lib/Resource/RoleCreatedData.php new file mode 100644 index 00000000..640924ef --- /dev/null +++ b/lib/Resource/RoleCreatedData.php @@ -0,0 +1,56 @@ +|null + */ + public ?array $permissions = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + slug: $data['slug'], + resourceTypeSlug: $data['resource_type_slug'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + permissions: $data['permissions'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'slug' => $this->slug, + 'resource_type_slug' => $this->resourceTypeSlug, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'permissions' => $this->permissions, + ]; + } +} diff --git a/lib/Resource/RoleDeleted.php b/lib/Resource/RoleDeleted.php new file mode 100644 index 00000000..0df50e16 --- /dev/null +++ b/lib/Resource/RoleDeleted.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/RoleDeletedContext.php b/lib/Resource/RoleDeletedContext.php new file mode 100644 index 00000000..d972d148 --- /dev/null +++ b/lib/Resource/RoleDeletedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?RoleDeletedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? RoleDeletedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/RoleDeletedContextActor.php b/lib/Resource/RoleDeletedContextActor.php new file mode 100644 index 00000000..6edf643e --- /dev/null +++ b/lib/Resource/RoleDeletedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/RoleDeletedContextGoogleAnalyticsSession.php b/lib/Resource/RoleDeletedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..94f7e70f --- /dev/null +++ b/lib/Resource/RoleDeletedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/RoleDeletedData.php b/lib/Resource/RoleDeletedData.php new file mode 100644 index 00000000..37457fa4 --- /dev/null +++ b/lib/Resource/RoleDeletedData.php @@ -0,0 +1,56 @@ +|null + */ + public ?array $permissions = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + slug: $data['slug'], + resourceTypeSlug: $data['resource_type_slug'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + permissions: $data['permissions'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'slug' => $this->slug, + 'resource_type_slug' => $this->resourceTypeSlug, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'permissions' => $this->permissions, + ]; + } +} diff --git a/lib/Resource/RoleList.php b/lib/Resource/RoleList.php new file mode 100644 index 00000000..10bd94e0 --- /dev/null +++ b/lib/Resource/RoleList.php @@ -0,0 +1,38 @@ + + */ + public array $data, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + data: array_map(fn ($item) => Role::fromArray($item), $data['data']), + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'data' => array_map(fn ($item) => $item->toArray(), $this->data), + ]; + } +} diff --git a/lib/Resource/RoleResponse.php b/lib/Resource/RoleResponse.php deleted file mode 100644 index 3e1686b5..00000000 --- a/lib/Resource/RoleResponse.php +++ /dev/null @@ -1,18 +0,0 @@ -slug = $slug; - } -} diff --git a/lib/Resource/RoleType.php b/lib/Resource/RoleType.php new file mode 100644 index 00000000..ad992f87 --- /dev/null +++ b/lib/Resource/RoleType.php @@ -0,0 +1,13 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/RoleUpdatedContext.php b/lib/Resource/RoleUpdatedContext.php new file mode 100644 index 00000000..4dd882ae --- /dev/null +++ b/lib/Resource/RoleUpdatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?RoleUpdatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? RoleUpdatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/RoleUpdatedContextActor.php b/lib/Resource/RoleUpdatedContextActor.php new file mode 100644 index 00000000..a5b9164b --- /dev/null +++ b/lib/Resource/RoleUpdatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/RoleUpdatedContextGoogleAnalyticsSession.php b/lib/Resource/RoleUpdatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..23dcc891 --- /dev/null +++ b/lib/Resource/RoleUpdatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/RoleUpdatedData.php b/lib/Resource/RoleUpdatedData.php new file mode 100644 index 00000000..b41c955f --- /dev/null +++ b/lib/Resource/RoleUpdatedData.php @@ -0,0 +1,56 @@ +|null + */ + public ?array $permissions = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + slug: $data['slug'], + resourceTypeSlug: $data['resource_type_slug'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + permissions: $data['permissions'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'slug' => $this->slug, + 'resource_type_slug' => $this->resourceTypeSlug, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'permissions' => $this->permissions, + ]; + } +} diff --git a/lib/Resource/SSOAuthorizeUrlResponse.php b/lib/Resource/SSOAuthorizeUrlResponse.php new file mode 100644 index 00000000..301b2fc2 --- /dev/null +++ b/lib/Resource/SSOAuthorizeUrlResponse.php @@ -0,0 +1,32 @@ + $this->url, + ]; + } +} diff --git a/lib/Resource/SSODeviceAuthorizationRequest.php b/lib/Resource/SSODeviceAuthorizationRequest.php new file mode 100644 index 00000000..6778acfa --- /dev/null +++ b/lib/Resource/SSODeviceAuthorizationRequest.php @@ -0,0 +1,32 @@ + $this->clientId, + ]; + } +} diff --git a/lib/Resource/SSOIntentOptions.php b/lib/Resource/SSOIntentOptions.php new file mode 100644 index 00000000..230acef2 --- /dev/null +++ b/lib/Resource/SSOIntentOptions.php @@ -0,0 +1,36 @@ + $this->bookmarkSlug, + 'provider_type' => $this->providerType, + ]; + } +} diff --git a/lib/Resource/SSOLogoutAuthorizeRequest.php b/lib/Resource/SSOLogoutAuthorizeRequest.php new file mode 100644 index 00000000..15e7a7ad --- /dev/null +++ b/lib/Resource/SSOLogoutAuthorizeRequest.php @@ -0,0 +1,32 @@ + $this->profileId, + ]; + } +} diff --git a/lib/Resource/SSOLogoutAuthorizeResponse.php b/lib/Resource/SSOLogoutAuthorizeResponse.php new file mode 100644 index 00000000..385724f5 --- /dev/null +++ b/lib/Resource/SSOLogoutAuthorizeResponse.php @@ -0,0 +1,36 @@ + $this->logoutUrl, + 'logout_token' => $this->logoutToken, + ]; + } +} diff --git a/lib/Resource/SSOProvider.php b/lib/Resource/SSOProvider.php new file mode 100644 index 00000000..619f93c0 --- /dev/null +++ b/lib/Resource/SSOProvider.php @@ -0,0 +1,15 @@ + $this->tokenType, + 'access_token' => $this->accessToken, + 'expires_in' => $this->expiresIn, + 'profile' => $this->profile->toArray(), + 'oauth_tokens' => $this->oauthTokens?->toArray(), + ]; + } +} diff --git a/lib/Resource/SSOTokenResponseOAuthToken.php b/lib/Resource/SSOTokenResponseOAuthToken.php new file mode 100644 index 00000000..65f163e3 --- /dev/null +++ b/lib/Resource/SSOTokenResponseOAuthToken.php @@ -0,0 +1,52 @@ + + */ + public array $scopes, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + provider: $data['provider'], + refreshToken: $data['refresh_token'], + accessToken: $data['access_token'], + expiresAt: $data['expires_at'], + scopes: $data['scopes'], + ); + } + + public function toArray(): array + { + return [ + 'provider' => $this->provider, + 'refresh_token' => $this->refreshToken, + 'access_token' => $this->accessToken, + 'expires_at' => $this->expiresAt, + 'scopes' => $this->scopes, + ]; + } +} diff --git a/lib/Resource/SendEmailChange.php b/lib/Resource/SendEmailChange.php new file mode 100644 index 00000000..3750e119 --- /dev/null +++ b/lib/Resource/SendEmailChange.php @@ -0,0 +1,32 @@ + $this->newEmail, + ]; + } +} diff --git a/lib/Resource/SendVerificationEmailResponse.php b/lib/Resource/SendVerificationEmailResponse.php new file mode 100644 index 00000000..e7d478d7 --- /dev/null +++ b/lib/Resource/SendVerificationEmailResponse.php @@ -0,0 +1,32 @@ + $this->user->toArray(), + ]; + } +} diff --git a/lib/Resource/Session.php b/lib/Resource/Session.php deleted file mode 100644 index 9c21dd4a..00000000 --- a/lib/Resource/Session.php +++ /dev/null @@ -1,54 +0,0 @@ - "id", - "user_id" => "userId", - "ip_address" => "ipAddress", - "user_agent" => "userAgent", - "organization_id" => "organizationId", - "authentication_method" => "authenticationMethod", - "status" => "status", - "expires_at" => "expiresAt", - "ended_at" => "endedAt", - "created_at" => "createdAt", - "updated_at" => "updatedAt", - "object" => "object" - ]; -} diff --git a/lib/Resource/SessionAuthenticationFailureResponse.php b/lib/Resource/SessionAuthenticationFailureResponse.php deleted file mode 100644 index b00aefb3..00000000 --- a/lib/Resource/SessionAuthenticationFailureResponse.php +++ /dev/null @@ -1,43 +0,0 @@ - "authenticated", - "reason" => "reason" - ]; - - /** - * Construct a failure response with a specific reason. - * - * @param string $reason Reason for authentication failure - */ - public function __construct(string $reason) - { - $this->values = [ - "authenticated" => false, - "reason" => $reason - ]; - $this->raw = []; - } -} diff --git a/lib/Resource/SessionAuthenticationSuccessResponse.php b/lib/Resource/SessionAuthenticationSuccessResponse.php deleted file mode 100644 index 049e37e4..00000000 --- a/lib/Resource/SessionAuthenticationSuccessResponse.php +++ /dev/null @@ -1,102 +0,0 @@ - "authenticated", - "access_token" => "accessToken", - "refresh_token" => "refreshToken", - "session_id" => "sessionId", - "user" => "user", - "organization_id" => "organizationId", - "role" => "role", - "roles" => "roles", - "permissions" => "permissions", - "entitlements" => "entitlements", - "feature_flags" => "featureFlags", - "impersonator" => "impersonator", - "authentication_method" => "authenticationMethod" - ]; - - public static function constructFromResponse($response) - { - $instance = parent::constructFromResponse($response); - - // Always set authenticated to true for success responses - $instance->values["authenticated"] = true; - - // Construct User resource from user data - if (isset($response["user"])) { - $instance->values["user"] = User::constructFromResponse($response["user"]); - } - - // Construct Role if present - if (isset($response["role"])) { - $instance->values["role"] = new RoleResponse($response["role"]["slug"]); - } - - // Construct Roles array if present - if (isset($response["roles"])) { - $roles = []; - foreach ($response["roles"] as $role) { - $roles[] = new RoleResponse($role["slug"]); - } - $instance->values["roles"] = $roles; - } - - // Construct FeatureFlags array if present - if (isset($response["feature_flags"])) { - $featureFlags = []; - foreach ($response["feature_flags"] as $flag) { - $featureFlags[] = FeatureFlag::constructFromResponse($flag); - } - $instance->values["featureFlags"] = $featureFlags; - } - - // Construct Impersonator if present - if (isset($response["impersonator"])) { - $instance->values["impersonator"] = Impersonator::constructFromResponse( - $response["impersonator"] - ); - } - - return $instance; - } -} diff --git a/lib/Resource/SessionCreated.php b/lib/Resource/SessionCreated.php new file mode 100644 index 00000000..e82f8478 --- /dev/null +++ b/lib/Resource/SessionCreated.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/SessionCreatedContext.php b/lib/Resource/SessionCreatedContext.php new file mode 100644 index 00000000..ccdd0674 --- /dev/null +++ b/lib/Resource/SessionCreatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?SessionCreatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? SessionCreatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/SessionCreatedContextActor.php b/lib/Resource/SessionCreatedContextActor.php new file mode 100644 index 00000000..86ec1164 --- /dev/null +++ b/lib/Resource/SessionCreatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/SessionCreatedContextGoogleAnalyticsSession.php b/lib/Resource/SessionCreatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..2f8ee1a5 --- /dev/null +++ b/lib/Resource/SessionCreatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/SessionCreatedData.php b/lib/Resource/SessionCreatedData.php new file mode 100644 index 00000000..2feba806 --- /dev/null +++ b/lib/Resource/SessionCreatedData.php @@ -0,0 +1,81 @@ + $this->object, + 'id' => $this->id, + 'ip_address' => $this->ipAddress, + 'user_agent' => $this->userAgent, + 'user_id' => $this->userId, + 'auth_method' => $this->authMethod->value, + 'status' => $this->status->value, + 'expires_at' => $this->expiresAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'ended_at' => $this->endedAt?->format(\DateTimeInterface::RFC3339_EXTENDED), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'impersonator' => $this->impersonator?->toArray(), + 'organization_id' => $this->organizationId, + ]; + } +} diff --git a/lib/Resource/SessionCreatedDataImpersonator.php b/lib/Resource/SessionCreatedDataImpersonator.php new file mode 100644 index 00000000..ac2faa9f --- /dev/null +++ b/lib/Resource/SessionCreatedDataImpersonator.php @@ -0,0 +1,37 @@ + $this->email, + 'reason' => $this->reason, + ]; + } +} diff --git a/lib/Resource/SessionRevoked.php b/lib/Resource/SessionRevoked.php new file mode 100644 index 00000000..c4048971 --- /dev/null +++ b/lib/Resource/SessionRevoked.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/SessionRevokedContext.php b/lib/Resource/SessionRevokedContext.php new file mode 100644 index 00000000..bcd4b45e --- /dev/null +++ b/lib/Resource/SessionRevokedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?SessionRevokedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? SessionRevokedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/SessionRevokedContextActor.php b/lib/Resource/SessionRevokedContextActor.php new file mode 100644 index 00000000..54de2abe --- /dev/null +++ b/lib/Resource/SessionRevokedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/SessionRevokedContextGoogleAnalyticsSession.php b/lib/Resource/SessionRevokedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..bf7835f3 --- /dev/null +++ b/lib/Resource/SessionRevokedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/SessionRevokedData.php b/lib/Resource/SessionRevokedData.php new file mode 100644 index 00000000..e50360e5 --- /dev/null +++ b/lib/Resource/SessionRevokedData.php @@ -0,0 +1,81 @@ + $this->object, + 'id' => $this->id, + 'ip_address' => $this->ipAddress, + 'user_agent' => $this->userAgent, + 'user_id' => $this->userId, + 'auth_method' => $this->authMethod->value, + 'status' => $this->status->value, + 'expires_at' => $this->expiresAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'ended_at' => $this->endedAt?->format(\DateTimeInterface::RFC3339_EXTENDED), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'impersonator' => $this->impersonator?->toArray(), + 'organization_id' => $this->organizationId, + ]; + } +} diff --git a/lib/Resource/SessionRevokedDataImpersonator.php b/lib/Resource/SessionRevokedDataImpersonator.php new file mode 100644 index 00000000..389cdf73 --- /dev/null +++ b/lib/Resource/SessionRevokedDataImpersonator.php @@ -0,0 +1,37 @@ + $this->email, + 'reason' => $this->reason, + ]; + } +} diff --git a/lib/Resource/SetRolePermissions.php b/lib/Resource/SetRolePermissions.php new file mode 100644 index 00000000..cf913f20 --- /dev/null +++ b/lib/Resource/SetRolePermissions.php @@ -0,0 +1,35 @@ + + */ + public array $permissions, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + permissions: $data['permissions'], + ); + } + + public function toArray(): array + { + return [ + 'permissions' => $this->permissions, + ]; + } +} diff --git a/lib/Resource/SlimRole.php b/lib/Resource/SlimRole.php new file mode 100644 index 00000000..609875cb --- /dev/null +++ b/lib/Resource/SlimRole.php @@ -0,0 +1,33 @@ + $this->slug, + ]; + } +} diff --git a/lib/Resource/TokenQuery.php b/lib/Resource/TokenQuery.php new file mode 100644 index 00000000..b21edca0 --- /dev/null +++ b/lib/Resource/TokenQuery.php @@ -0,0 +1,44 @@ + $this->clientId, + 'client_secret' => $this->clientSecret, + 'code' => $this->code, + 'grant_type' => $this->grantType, + ]; + } +} diff --git a/lib/Resource/UpdateAuditLogsRetention.php b/lib/Resource/UpdateAuditLogsRetention.php new file mode 100644 index 00000000..35edb779 --- /dev/null +++ b/lib/Resource/UpdateAuditLogsRetention.php @@ -0,0 +1,32 @@ + $this->retentionPeriodInDays, + ]; + } +} diff --git a/lib/Resource/UpdateAuthorizationPermission.php b/lib/Resource/UpdateAuthorizationPermission.php new file mode 100644 index 00000000..998ca65e --- /dev/null +++ b/lib/Resource/UpdateAuthorizationPermission.php @@ -0,0 +1,36 @@ + $this->name, + 'description' => $this->description, + ]; + } +} diff --git a/lib/Resource/UpdateAuthorizationResource.php b/lib/Resource/UpdateAuthorizationResource.php new file mode 100644 index 00000000..90134482 --- /dev/null +++ b/lib/Resource/UpdateAuthorizationResource.php @@ -0,0 +1,48 @@ + $this->name, + 'description' => $this->description, + 'parent_resource_id' => $this->parentResourceId, + 'parent_resource_external_id' => $this->parentResourceExternalId, + 'parent_resource_type_slug' => $this->parentResourceTypeSlug, + ]; + } +} diff --git a/lib/Resource/UpdateJWTTemplate.php b/lib/Resource/UpdateJWTTemplate.php new file mode 100644 index 00000000..8a071c1d --- /dev/null +++ b/lib/Resource/UpdateJWTTemplate.php @@ -0,0 +1,32 @@ + $this->content, + ]; + } +} diff --git a/lib/Resource/UpdateOAuthApplication.php b/lib/Resource/UpdateOAuthApplication.php new file mode 100644 index 00000000..094a498a --- /dev/null +++ b/lib/Resource/UpdateOAuthApplication.php @@ -0,0 +1,50 @@ +|null + */ + public ?array $scopes = null, + /** + * Updated redirect URIs for the application. OAuth applications only. + * @var array<\WorkOS\Resource\RedirectUriInput>|null + */ + public ?array $redirectUris = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + name: $data['name'] ?? null, + description: $data['description'] ?? null, + scopes: $data['scopes'] ?? null, + redirectUris: isset($data['redirect_uris']) ? array_map(fn ($item) => RedirectUriInput::fromArray($item), $data['redirect_uris']) : null, + ); + } + + public function toArray(): array + { + return [ + 'name' => $this->name, + 'description' => $this->description, + 'scopes' => $this->scopes, + 'redirect_uris' => $this->redirectUris !== null ? array_map(fn ($item) => $item->toArray(), $this->redirectUris) : null, + ]; + } +} diff --git a/lib/Resource/UpdateOrganization.php b/lib/Resource/UpdateOrganization.php new file mode 100644 index 00000000..9c8b0ebe --- /dev/null +++ b/lib/Resource/UpdateOrganization.php @@ -0,0 +1,66 @@ +|null + * @deprecated + */ + public ?array $domains = null, + /** + * The domains associated with the organization, including verification state. + * @var array<\WorkOS\Resource\OrganizationDomainData>|null + */ + public ?array $domainData = null, + /** The Stripe customer ID associated with the organization. */ + public ?string $stripeCustomerId = null, + /** + * Object containing [metadata](https://workos.com/docs/authkit/metadata) key/value pairs associated with the Organization. + * @var array|null + */ + public ?array $metadata = null, + /** An external identifier for the Organization. */ + public ?string $externalId = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + name: $data['name'] ?? null, + allowProfilesOutsideOrganization: $data['allow_profiles_outside_organization'] ?? null, + domains: $data['domains'] ?? null, + domainData: isset($data['domain_data']) ? array_map(fn ($item) => OrganizationDomainData::fromArray($item), $data['domain_data']) : null, + stripeCustomerId: $data['stripe_customer_id'] ?? null, + metadata: $data['metadata'] ?? null, + externalId: $data['external_id'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'name' => $this->name, + 'allow_profiles_outside_organization' => $this->allowProfilesOutsideOrganization, + 'domains' => $this->domains, + 'domain_data' => $this->domainData !== null ? array_map(fn ($item) => $item->toArray(), $this->domainData) : null, + 'stripe_customer_id' => $this->stripeCustomerId, + 'metadata' => $this->metadata, + 'external_id' => $this->externalId, + ]; + } +} diff --git a/lib/Resource/UpdateOrganizationRole.php b/lib/Resource/UpdateOrganizationRole.php new file mode 100644 index 00000000..84611fbe --- /dev/null +++ b/lib/Resource/UpdateOrganizationRole.php @@ -0,0 +1,36 @@ + $this->name, + 'description' => $this->description, + ]; + } +} diff --git a/lib/Resource/UpdateRole.php b/lib/Resource/UpdateRole.php new file mode 100644 index 00000000..4373c2da --- /dev/null +++ b/lib/Resource/UpdateRole.php @@ -0,0 +1,36 @@ + $this->name, + 'description' => $this->description, + ]; + } +} diff --git a/lib/Resource/UpdateUser.php b/lib/Resource/UpdateUser.php new file mode 100644 index 00000000..cb3520b2 --- /dev/null +++ b/lib/Resource/UpdateUser.php @@ -0,0 +1,71 @@ +|null + */ + public ?array $metadata = null, + /** The external ID of the user. */ + public ?string $externalId = null, + /** The user's preferred locale. */ + public ?string $locale = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + email: $data['email'] ?? null, + firstName: $data['first_name'] ?? null, + lastName: $data['last_name'] ?? null, + emailVerified: $data['email_verified'] ?? null, + password: $data['password'] ?? null, + passwordHash: $data['password_hash'] ?? null, + passwordHashType: isset($data['password_hash_type']) ? CreateUserPasswordHashType::from($data['password_hash_type']) : null, + metadata: $data['metadata'] ?? null, + externalId: $data['external_id'] ?? null, + locale: $data['locale'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'email' => $this->email, + 'first_name' => $this->firstName, + 'last_name' => $this->lastName, + 'email_verified' => $this->emailVerified, + 'password' => $this->password, + 'password_hash' => $this->passwordHash, + 'password_hash_type' => $this->passwordHashType?->value, + 'metadata' => $this->metadata, + 'external_id' => $this->externalId, + 'locale' => $this->locale, + ]; + } +} diff --git a/lib/Resource/UpdateUserOrganizationMembership.php b/lib/Resource/UpdateUserOrganizationMembership.php new file mode 100644 index 00000000..78c27a3b --- /dev/null +++ b/lib/Resource/UpdateUserOrganizationMembership.php @@ -0,0 +1,39 @@ +|null + */ + public ?array $roleSlugs = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + roleSlug: $data['role_slug'] ?? null, + roleSlugs: $data['role_slugs'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'role_slug' => $this->roleSlug, + 'role_slugs' => $this->roleSlugs, + ]; + } +} diff --git a/lib/Resource/UpdateUserPasswordHashType.php b/lib/Resource/UpdateUserPasswordHashType.php new file mode 100644 index 00000000..c6d9ffca --- /dev/null +++ b/lib/Resource/UpdateUserPasswordHashType.php @@ -0,0 +1,17 @@ +|null + */ + public ?array $events = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + endpointUrl: $data['endpoint_url'] ?? null, + status: isset($data['status']) ? WebhookEndpointJsonStatus::from($data['status']) : null, + events: isset($data['events']) ? array_map(fn ($item) => CreateWebhookEndpointEvents::from($item), $data['events']) : null, + ); + } + + public function toArray(): array + { + return [ + 'endpoint_url' => $this->endpointUrl, + 'status' => $this->status?->value, + 'events' => $this->events !== null ? array_map(fn ($item) => $item->value, $this->events) : null, + ]; + } +} diff --git a/lib/Resource/UpdateWebhookEndpointEvents.php b/lib/Resource/UpdateWebhookEndpointEvents.php new file mode 100644 index 00000000..806a0f85 --- /dev/null +++ b/lib/Resource/UpdateWebhookEndpointEvents.php @@ -0,0 +1,80 @@ +|null + */ + public ?array $metadata = null, + /** The user's preferred locale. */ + public ?string $locale = null, + ) { + } - public const RESOURCE_ATTRIBUTES = [ - "object", - "id", - "email", - "firstName", - "lastName", - "emailVerified", - "profilePictureUrl", - "lastSignInAt", - "createdAt", - "updatedAt", - "externalId", - "metadata" - ]; + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + firstName: $data['first_name'] ?? null, + lastName: $data['last_name'] ?? null, + profilePictureUrl: $data['profile_picture_url'] ?? null, + email: $data['email'], + emailVerified: $data['email_verified'], + externalId: $data['external_id'] ?? null, + lastSignInAt: isset($data['last_sign_in_at']) ? new \DateTimeImmutable($data['last_sign_in_at']) : null, + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + metadata: $data['metadata'] ?? null, + locale: $data['locale'] ?? null, + ); + } - public const RESPONSE_TO_RESOURCE_KEY = [ - "object" => "object", - "id" => "id", - "email" => "email", - "first_name" => "firstName", - "last_name" => "lastName", - "email_verified" => "emailVerified", - "profile_picture_url" => "profilePictureUrl", - "last_sign_in_at" => "lastSignInAt", - "created_at" => "createdAt", - "updated_at" => "updatedAt", - "external_id" => "externalId", - "metadata" => "metadata" - ]; + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'first_name' => $this->firstName, + 'last_name' => $this->lastName, + 'profile_picture_url' => $this->profilePictureUrl, + 'email' => $this->email, + 'email_verified' => $this->emailVerified, + 'external_id' => $this->externalId, + 'last_sign_in_at' => $this->lastSignInAt?->format(\DateTimeInterface::RFC3339_EXTENDED), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'metadata' => $this->metadata, + 'locale' => $this->locale, + ]; + } } diff --git a/lib/Resource/UserAndToken.php b/lib/Resource/UserAndToken.php deleted file mode 100644 index 3e73358a..00000000 --- a/lib/Resource/UserAndToken.php +++ /dev/null @@ -1,30 +0,0 @@ - "token" - ]; - - public static function constructFromResponse($response) - { - $instance = parent::constructFromResponse($response); - - $instance->values["user"] = User::constructFromResponse($response["user"]); - - return $instance; - } -} diff --git a/lib/Resource/UserAuthenticationFactorEnrollResponse.php b/lib/Resource/UserAuthenticationFactorEnrollResponse.php new file mode 100644 index 00000000..ced8dfb7 --- /dev/null +++ b/lib/Resource/UserAuthenticationFactorEnrollResponse.php @@ -0,0 +1,36 @@ + $this->authenticationFactor->toArray(), + 'authentication_challenge' => $this->authenticationChallenge->toArray(), + ]; + } +} diff --git a/lib/Resource/UserAuthenticationFactorTotp.php b/lib/Resource/UserAuthenticationFactorTotp.php deleted file mode 100644 index 052599a5..00000000 --- a/lib/Resource/UserAuthenticationFactorTotp.php +++ /dev/null @@ -1,31 +0,0 @@ - "object", - "id" => "id", - "user_id" => "userId", - "created_at" => "createdAt", - "updated_at" => "updatedAt", - "type" => "type", - "totp" => "totp" - ]; -} diff --git a/lib/Resource/UserConsentOption.php b/lib/Resource/UserConsentOption.php new file mode 100644 index 00000000..e8dd0b9c --- /dev/null +++ b/lib/Resource/UserConsentOption.php @@ -0,0 +1,47 @@ + + */ + public array $choices, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + claim: $data['claim'], + type: $data['type'], + label: $data['label'], + choices: array_map(fn ($item) => UserConsentOptionChoice::fromArray($item), $data['choices']), + ); + } + + public function toArray(): array + { + return [ + 'claim' => $this->claim, + 'type' => $this->type, + 'label' => $this->label, + 'choices' => array_map(fn ($item) => $item->toArray(), $this->choices), + ]; + } +} diff --git a/lib/Resource/UserConsentOptionChoice.php b/lib/Resource/UserConsentOptionChoice.php new file mode 100644 index 00000000..251c141d --- /dev/null +++ b/lib/Resource/UserConsentOptionChoice.php @@ -0,0 +1,36 @@ + $this->value, + 'label' => $this->label, + ]; + } +} diff --git a/lib/Resource/UserCreated.php b/lib/Resource/UserCreated.php new file mode 100644 index 00000000..023b739a --- /dev/null +++ b/lib/Resource/UserCreated.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/UserCreatedContext.php b/lib/Resource/UserCreatedContext.php new file mode 100644 index 00000000..2252b8d3 --- /dev/null +++ b/lib/Resource/UserCreatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?UserCreatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? UserCreatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/UserCreatedContextActor.php b/lib/Resource/UserCreatedContextActor.php new file mode 100644 index 00000000..daa12bff --- /dev/null +++ b/lib/Resource/UserCreatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/UserCreatedContextGoogleAnalyticsSession.php b/lib/Resource/UserCreatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..4b706277 --- /dev/null +++ b/lib/Resource/UserCreatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/UserCreatedData.php b/lib/Resource/UserCreatedData.php new file mode 100644 index 00000000..d29b49b2 --- /dev/null +++ b/lib/Resource/UserCreatedData.php @@ -0,0 +1,84 @@ +|null + */ + public ?array $metadata = null, + /** The user's preferred locale. */ + public ?string $locale = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + firstName: $data['first_name'] ?? null, + lastName: $data['last_name'] ?? null, + profilePictureUrl: $data['profile_picture_url'] ?? null, + email: $data['email'], + emailVerified: $data['email_verified'], + externalId: $data['external_id'] ?? null, + lastSignInAt: isset($data['last_sign_in_at']) ? new \DateTimeImmutable($data['last_sign_in_at']) : null, + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + metadata: $data['metadata'] ?? null, + locale: $data['locale'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'first_name' => $this->firstName, + 'last_name' => $this->lastName, + 'profile_picture_url' => $this->profilePictureUrl, + 'email' => $this->email, + 'email_verified' => $this->emailVerified, + 'external_id' => $this->externalId, + 'last_sign_in_at' => $this->lastSignInAt?->format(\DateTimeInterface::RFC3339_EXTENDED), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'metadata' => $this->metadata, + 'locale' => $this->locale, + ]; + } +} diff --git a/lib/Resource/UserDeleted.php b/lib/Resource/UserDeleted.php new file mode 100644 index 00000000..5d5e2922 --- /dev/null +++ b/lib/Resource/UserDeleted.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/UserDeletedContext.php b/lib/Resource/UserDeletedContext.php new file mode 100644 index 00000000..56ecfbbe --- /dev/null +++ b/lib/Resource/UserDeletedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?UserDeletedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? UserDeletedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/UserDeletedContextActor.php b/lib/Resource/UserDeletedContextActor.php new file mode 100644 index 00000000..b95ce54a --- /dev/null +++ b/lib/Resource/UserDeletedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/UserDeletedContextGoogleAnalyticsSession.php b/lib/Resource/UserDeletedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..45691ffb --- /dev/null +++ b/lib/Resource/UserDeletedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/UserDeletedData.php b/lib/Resource/UserDeletedData.php new file mode 100644 index 00000000..1445ab94 --- /dev/null +++ b/lib/Resource/UserDeletedData.php @@ -0,0 +1,84 @@ +|null + */ + public ?array $metadata = null, + /** The user's preferred locale. */ + public ?string $locale = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + firstName: $data['first_name'] ?? null, + lastName: $data['last_name'] ?? null, + profilePictureUrl: $data['profile_picture_url'] ?? null, + email: $data['email'], + emailVerified: $data['email_verified'], + externalId: $data['external_id'] ?? null, + lastSignInAt: isset($data['last_sign_in_at']) ? new \DateTimeImmutable($data['last_sign_in_at']) : null, + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + metadata: $data['metadata'] ?? null, + locale: $data['locale'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'first_name' => $this->firstName, + 'last_name' => $this->lastName, + 'profile_picture_url' => $this->profilePictureUrl, + 'email' => $this->email, + 'email_verified' => $this->emailVerified, + 'external_id' => $this->externalId, + 'last_sign_in_at' => $this->lastSignInAt?->format(\DateTimeInterface::RFC3339_EXTENDED), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'metadata' => $this->metadata, + 'locale' => $this->locale, + ]; + } +} diff --git a/lib/Resource/UserIdentitiesGetItem.php b/lib/Resource/UserIdentitiesGetItem.php new file mode 100644 index 00000000..9e03ae1f --- /dev/null +++ b/lib/Resource/UserIdentitiesGetItem.php @@ -0,0 +1,40 @@ + $this->idpId, + 'type' => $this->type, + 'provider' => $this->provider->value, + ]; + } +} diff --git a/lib/Resource/UserIdentitiesGetItemProvider.php b/lib/Resource/UserIdentitiesGetItemProvider.php new file mode 100644 index 00000000..6c4564a9 --- /dev/null +++ b/lib/Resource/UserIdentitiesGetItemProvider.php @@ -0,0 +1,25 @@ + $this->object, + 'id' => $this->id, + 'email' => $this->email, + 'state' => $this->state->value, + 'accepted_at' => $this->acceptedAt?->format(\DateTimeInterface::RFC3339_EXTENDED), + 'revoked_at' => $this->revokedAt?->format(\DateTimeInterface::RFC3339_EXTENDED), + 'expires_at' => $this->expiresAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'organization_id' => $this->organizationId, + 'inviter_user_id' => $this->inviterUserId, + 'accepted_user_id' => $this->acceptedUserId, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'token' => $this->token, + 'accept_invitation_url' => $this->acceptInvitationUrl, + ]; + } +} diff --git a/lib/Resource/UserInviteState.php b/lib/Resource/UserInviteState.php new file mode 100644 index 00000000..f7fc57da --- /dev/null +++ b/lib/Resource/UserInviteState.php @@ -0,0 +1,15 @@ +|null + */ + public ?array $userConsentOptions = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + externalAuthId: $data['external_auth_id'], + user: UserObject::fromArray($data['user']), + userConsentOptions: isset($data['user_consent_options']) ? array_map(fn ($item) => UserConsentOption::fromArray($item), $data['user_consent_options']) : null, + ); + } + + public function toArray(): array + { + return [ + 'external_auth_id' => $this->externalAuthId, + 'user' => $this->user->toArray(), + 'user_consent_options' => $this->userConsentOptions !== null ? array_map(fn ($item) => $item->toArray(), $this->userConsentOptions) : null, + ]; + } +} diff --git a/lib/Resource/UserManagementMultiFactorAuthenticationOrder.php b/lib/Resource/UserManagementMultiFactorAuthenticationOrder.php new file mode 100644 index 00000000..87ebfee2 --- /dev/null +++ b/lib/Resource/UserManagementMultiFactorAuthenticationOrder.php @@ -0,0 +1,14 @@ +|null + */ + public ?array $metadata = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + id: $data['id'], + email: $data['email'], + firstName: $data['first_name'] ?? null, + lastName: $data['last_name'] ?? null, + metadata: $data['metadata'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'id' => $this->id, + 'email' => $this->email, + 'first_name' => $this->firstName, + 'last_name' => $this->lastName, + 'metadata' => $this->metadata, + ]; + } +} diff --git a/lib/Resource/UserOrganizationMembership.php b/lib/Resource/UserOrganizationMembership.php new file mode 100644 index 00000000..8d53ba6e --- /dev/null +++ b/lib/Resource/UserOrganizationMembership.php @@ -0,0 +1,75 @@ +|null + */ + public ?array $customAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + userId: $data['user_id'], + organizationId: $data['organization_id'], + status: OrganizationMembershipStatus::from($data['status']), + directoryManaged: $data['directory_managed'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + role: SlimRole::fromArray($data['role']), + organizationName: $data['organization_name'] ?? null, + customAttributes: $data['custom_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'user_id' => $this->userId, + 'organization_id' => $this->organizationId, + 'status' => $this->status->value, + 'directory_managed' => $this->directoryManaged, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'role' => $this->role->toArray(), + 'organization_name' => $this->organizationName, + 'custom_attributes' => $this->customAttributes, + ]; + } +} diff --git a/lib/Resource/UserOrganizationMembershipBaseListData.php b/lib/Resource/UserOrganizationMembershipBaseListData.php new file mode 100644 index 00000000..0013b6d9 --- /dev/null +++ b/lib/Resource/UserOrganizationMembershipBaseListData.php @@ -0,0 +1,71 @@ +|null + */ + public ?array $customAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + userId: $data['user_id'], + organizationId: $data['organization_id'], + status: OrganizationMembershipStatus::from($data['status']), + directoryManaged: $data['directory_managed'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + organizationName: $data['organization_name'] ?? null, + customAttributes: $data['custom_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'user_id' => $this->userId, + 'organization_id' => $this->organizationId, + 'status' => $this->status->value, + 'directory_managed' => $this->directoryManaged, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'organization_name' => $this->organizationName, + 'custom_attributes' => $this->customAttributes, + ]; + } +} diff --git a/lib/Resource/UserOrganizationMembershipBaseListDataStatus.php b/lib/Resource/UserOrganizationMembershipBaseListDataStatus.php new file mode 100644 index 00000000..12ba7fd5 --- /dev/null +++ b/lib/Resource/UserOrganizationMembershipBaseListDataStatus.php @@ -0,0 +1,14 @@ +values["user"] = User::constructFromResponse($response["user"]); - - return $instance; - } -} diff --git a/lib/Resource/UserSessionsAuthMethod.php b/lib/Resource/UserSessionsAuthMethod.php new file mode 100644 index 00000000..6c363bea --- /dev/null +++ b/lib/Resource/UserSessionsAuthMethod.php @@ -0,0 +1,21 @@ + $this->email, + 'reason' => $this->reason, + ]; + } +} diff --git a/lib/Resource/UserSessionsListItem.php b/lib/Resource/UserSessionsListItem.php new file mode 100644 index 00000000..6c70ef2c --- /dev/null +++ b/lib/Resource/UserSessionsListItem.php @@ -0,0 +1,80 @@ + $this->object, + 'id' => $this->id, + 'ip_address' => $this->ipAddress, + 'user_agent' => $this->userAgent, + 'user_id' => $this->userId, + 'auth_method' => $this->authMethod->value, + 'status' => $this->status->value, + 'expires_at' => $this->expiresAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'ended_at' => $this->endedAt?->format(\DateTimeInterface::RFC3339_EXTENDED), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'impersonator' => $this->impersonator?->toArray(), + 'organization_id' => $this->organizationId, + ]; + } +} diff --git a/lib/Resource/UserSessionsStatus.php b/lib/Resource/UserSessionsStatus.php new file mode 100644 index 00000000..530f4050 --- /dev/null +++ b/lib/Resource/UserSessionsStatus.php @@ -0,0 +1,14 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/UserUpdatedContext.php b/lib/Resource/UserUpdatedContext.php new file mode 100644 index 00000000..24b909fb --- /dev/null +++ b/lib/Resource/UserUpdatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?UserUpdatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? UserUpdatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/UserUpdatedContextActor.php b/lib/Resource/UserUpdatedContextActor.php new file mode 100644 index 00000000..dbca9bc2 --- /dev/null +++ b/lib/Resource/UserUpdatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/UserUpdatedContextGoogleAnalyticsSession.php b/lib/Resource/UserUpdatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..0e1fa524 --- /dev/null +++ b/lib/Resource/UserUpdatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/UserUpdatedData.php b/lib/Resource/UserUpdatedData.php new file mode 100644 index 00000000..4ff62ed3 --- /dev/null +++ b/lib/Resource/UserUpdatedData.php @@ -0,0 +1,84 @@ +|null + */ + public ?array $metadata = null, + /** The user's preferred locale. */ + public ?string $locale = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + firstName: $data['first_name'] ?? null, + lastName: $data['last_name'] ?? null, + profilePictureUrl: $data['profile_picture_url'] ?? null, + email: $data['email'], + emailVerified: $data['email_verified'], + externalId: $data['external_id'] ?? null, + lastSignInAt: isset($data['last_sign_in_at']) ? new \DateTimeImmutable($data['last_sign_in_at']) : null, + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + metadata: $data['metadata'] ?? null, + locale: $data['locale'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'first_name' => $this->firstName, + 'last_name' => $this->lastName, + 'profile_picture_url' => $this->profilePictureUrl, + 'email' => $this->email, + 'email_verified' => $this->emailVerified, + 'external_id' => $this->externalId, + 'last_sign_in_at' => $this->lastSignInAt?->format(\DateTimeInterface::RFC3339_EXTENDED), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'metadata' => $this->metadata, + 'locale' => $this->locale, + ]; + } +} diff --git a/lib/Resource/ValidateApiKey.php b/lib/Resource/ValidateApiKey.php new file mode 100644 index 00000000..98c2f3c0 --- /dev/null +++ b/lib/Resource/ValidateApiKey.php @@ -0,0 +1,32 @@ + $this->value, + ]; + } +} diff --git a/lib/Resource/VaultByokKeyVerificationCompleted.php b/lib/Resource/VaultByokKeyVerificationCompleted.php new file mode 100644 index 00000000..afb4cfe3 --- /dev/null +++ b/lib/Resource/VaultByokKeyVerificationCompleted.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/VaultByokKeyVerificationCompletedContext.php b/lib/Resource/VaultByokKeyVerificationCompletedContext.php new file mode 100644 index 00000000..ad36875a --- /dev/null +++ b/lib/Resource/VaultByokKeyVerificationCompletedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?VaultByokKeyVerificationCompletedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? VaultByokKeyVerificationCompletedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/VaultByokKeyVerificationCompletedContextActor.php b/lib/Resource/VaultByokKeyVerificationCompletedContextActor.php new file mode 100644 index 00000000..8f4eadaf --- /dev/null +++ b/lib/Resource/VaultByokKeyVerificationCompletedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/VaultByokKeyVerificationCompletedContextGoogleAnalyticsSession.php b/lib/Resource/VaultByokKeyVerificationCompletedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..8a619cd4 --- /dev/null +++ b/lib/Resource/VaultByokKeyVerificationCompletedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/VaultByokKeyVerificationCompletedData.php b/lib/Resource/VaultByokKeyVerificationCompletedData.php new file mode 100644 index 00000000..a23530c3 --- /dev/null +++ b/lib/Resource/VaultByokKeyVerificationCompletedData.php @@ -0,0 +1,41 @@ + $this->organizationId, + 'key_provider' => $this->keyProvider->value, + 'verified' => $this->verified, + ]; + } +} diff --git a/lib/Resource/VaultByokKeyVerificationCompletedDataKeyProvider.php b/lib/Resource/VaultByokKeyVerificationCompletedDataKeyProvider.php new file mode 100644 index 00000000..f2786536 --- /dev/null +++ b/lib/Resource/VaultByokKeyVerificationCompletedDataKeyProvider.php @@ -0,0 +1,14 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/VaultDataCreatedContext.php b/lib/Resource/VaultDataCreatedContext.php new file mode 100644 index 00000000..942a91dc --- /dev/null +++ b/lib/Resource/VaultDataCreatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?VaultDataCreatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? VaultDataCreatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/VaultDataCreatedContextActor.php b/lib/Resource/VaultDataCreatedContextActor.php new file mode 100644 index 00000000..638d3829 --- /dev/null +++ b/lib/Resource/VaultDataCreatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/VaultDataCreatedContextGoogleAnalyticsSession.php b/lib/Resource/VaultDataCreatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..895e7acd --- /dev/null +++ b/lib/Resource/VaultDataCreatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/VaultDataCreatedData.php b/lib/Resource/VaultDataCreatedData.php new file mode 100644 index 00000000..12f2dd8a --- /dev/null +++ b/lib/Resource/VaultDataCreatedData.php @@ -0,0 +1,52 @@ + */ + public array $keyContext, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + actorId: $data['actor_id'], + actorSource: VaultDekReadDataActorSource::from($data['actor_source']), + actorName: $data['actor_name'], + kvName: $data['kv_name'], + keyId: $data['key_id'], + keyContext: $data['key_context'], + ); + } + + public function toArray(): array + { + return [ + 'actor_id' => $this->actorId, + 'actor_source' => $this->actorSource->value, + 'actor_name' => $this->actorName, + 'kv_name' => $this->kvName, + 'key_id' => $this->keyId, + 'key_context' => $this->keyContext, + ]; + } +} diff --git a/lib/Resource/VaultDataDeleted.php b/lib/Resource/VaultDataDeleted.php new file mode 100644 index 00000000..fdb1e01e --- /dev/null +++ b/lib/Resource/VaultDataDeleted.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/VaultDataDeletedContext.php b/lib/Resource/VaultDataDeletedContext.php new file mode 100644 index 00000000..e294e2e3 --- /dev/null +++ b/lib/Resource/VaultDataDeletedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?VaultDataDeletedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? VaultDataDeletedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/VaultDataDeletedContextActor.php b/lib/Resource/VaultDataDeletedContextActor.php new file mode 100644 index 00000000..6e0a22f6 --- /dev/null +++ b/lib/Resource/VaultDataDeletedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/VaultDataDeletedContextGoogleAnalyticsSession.php b/lib/Resource/VaultDataDeletedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..4b49eeef --- /dev/null +++ b/lib/Resource/VaultDataDeletedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/VaultDataDeletedData.php b/lib/Resource/VaultDataDeletedData.php new file mode 100644 index 00000000..ac96c157 --- /dev/null +++ b/lib/Resource/VaultDataDeletedData.php @@ -0,0 +1,44 @@ + $this->actorId, + 'actor_source' => $this->actorSource->value, + 'actor_name' => $this->actorName, + 'kv_name' => $this->kvName, + ]; + } +} diff --git a/lib/Resource/VaultDataRead.php b/lib/Resource/VaultDataRead.php new file mode 100644 index 00000000..690d59a8 --- /dev/null +++ b/lib/Resource/VaultDataRead.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/VaultDataReadContext.php b/lib/Resource/VaultDataReadContext.php new file mode 100644 index 00000000..c5d58a23 --- /dev/null +++ b/lib/Resource/VaultDataReadContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?VaultDataReadContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? VaultDataReadContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/VaultDataReadContextActor.php b/lib/Resource/VaultDataReadContextActor.php new file mode 100644 index 00000000..a343f98b --- /dev/null +++ b/lib/Resource/VaultDataReadContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/VaultDataReadContextGoogleAnalyticsSession.php b/lib/Resource/VaultDataReadContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..3aef9557 --- /dev/null +++ b/lib/Resource/VaultDataReadContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/VaultDataReadData.php b/lib/Resource/VaultDataReadData.php new file mode 100644 index 00000000..9a487a10 --- /dev/null +++ b/lib/Resource/VaultDataReadData.php @@ -0,0 +1,48 @@ + $this->actorId, + 'actor_source' => $this->actorSource->value, + 'actor_name' => $this->actorName, + 'kv_name' => $this->kvName, + 'key_id' => $this->keyId, + ]; + } +} diff --git a/lib/Resource/VaultDataUpdated.php b/lib/Resource/VaultDataUpdated.php new file mode 100644 index 00000000..d45e75b0 --- /dev/null +++ b/lib/Resource/VaultDataUpdated.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/VaultDataUpdatedContext.php b/lib/Resource/VaultDataUpdatedContext.php new file mode 100644 index 00000000..d8c8e168 --- /dev/null +++ b/lib/Resource/VaultDataUpdatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?VaultDataUpdatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? VaultDataUpdatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/VaultDataUpdatedContextActor.php b/lib/Resource/VaultDataUpdatedContextActor.php new file mode 100644 index 00000000..0918b203 --- /dev/null +++ b/lib/Resource/VaultDataUpdatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/VaultDataUpdatedContextGoogleAnalyticsSession.php b/lib/Resource/VaultDataUpdatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..61b480ae --- /dev/null +++ b/lib/Resource/VaultDataUpdatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/VaultDataUpdatedData.php b/lib/Resource/VaultDataUpdatedData.php new file mode 100644 index 00000000..c54f7c02 --- /dev/null +++ b/lib/Resource/VaultDataUpdatedData.php @@ -0,0 +1,52 @@ + */ + public array $keyContext, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + actorId: $data['actor_id'], + actorSource: VaultDekReadDataActorSource::from($data['actor_source']), + actorName: $data['actor_name'], + kvName: $data['kv_name'], + keyId: $data['key_id'], + keyContext: $data['key_context'], + ); + } + + public function toArray(): array + { + return [ + 'actor_id' => $this->actorId, + 'actor_source' => $this->actorSource->value, + 'actor_name' => $this->actorName, + 'kv_name' => $this->kvName, + 'key_id' => $this->keyId, + 'key_context' => $this->keyContext, + ]; + } +} diff --git a/lib/Resource/VaultDekDecrypted.php b/lib/Resource/VaultDekDecrypted.php new file mode 100644 index 00000000..f0c5f4a9 --- /dev/null +++ b/lib/Resource/VaultDekDecrypted.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/VaultDekDecryptedContext.php b/lib/Resource/VaultDekDecryptedContext.php new file mode 100644 index 00000000..a4841b74 --- /dev/null +++ b/lib/Resource/VaultDekDecryptedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?VaultDekDecryptedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? VaultDekDecryptedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/VaultDekDecryptedContextActor.php b/lib/Resource/VaultDekDecryptedContextActor.php new file mode 100644 index 00000000..5174765b --- /dev/null +++ b/lib/Resource/VaultDekDecryptedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/VaultDekDecryptedContextGoogleAnalyticsSession.php b/lib/Resource/VaultDekDecryptedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..d82e76ef --- /dev/null +++ b/lib/Resource/VaultDekDecryptedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/VaultDekDecryptedData.php b/lib/Resource/VaultDekDecryptedData.php new file mode 100644 index 00000000..710cd98d --- /dev/null +++ b/lib/Resource/VaultDekDecryptedData.php @@ -0,0 +1,44 @@ + $this->actorId, + 'actor_source' => $this->actorSource->value, + 'actor_name' => $this->actorName, + 'key_id' => $this->keyId, + ]; + } +} diff --git a/lib/Resource/VaultDekRead.php b/lib/Resource/VaultDekRead.php new file mode 100644 index 00000000..1bdc2189 --- /dev/null +++ b/lib/Resource/VaultDekRead.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/VaultDekReadContext.php b/lib/Resource/VaultDekReadContext.php new file mode 100644 index 00000000..a6800338 --- /dev/null +++ b/lib/Resource/VaultDekReadContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?VaultDekReadContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? VaultDekReadContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/VaultDekReadContextActor.php b/lib/Resource/VaultDekReadContextActor.php new file mode 100644 index 00000000..60b79dc5 --- /dev/null +++ b/lib/Resource/VaultDekReadContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/VaultDekReadContextGoogleAnalyticsSession.php b/lib/Resource/VaultDekReadContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..d6b85487 --- /dev/null +++ b/lib/Resource/VaultDekReadContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/VaultDekReadData.php b/lib/Resource/VaultDekReadData.php new file mode 100644 index 00000000..4195cc37 --- /dev/null +++ b/lib/Resource/VaultDekReadData.php @@ -0,0 +1,51 @@ + + */ + public array $keyIds, + /** @var array */ + public array $keyContext, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + actorId: $data['actor_id'], + actorSource: VaultDekReadDataActorSource::from($data['actor_source']), + actorName: $data['actor_name'], + keyIds: $data['key_ids'], + keyContext: $data['key_context'], + ); + } + + public function toArray(): array + { + return [ + 'actor_id' => $this->actorId, + 'actor_source' => $this->actorSource->value, + 'actor_name' => $this->actorName, + 'key_ids' => $this->keyIds, + 'key_context' => $this->keyContext, + ]; + } +} diff --git a/lib/Resource/VaultDekReadDataActorSource.php b/lib/Resource/VaultDekReadDataActorSource.php new file mode 100644 index 00000000..1c23d79a --- /dev/null +++ b/lib/Resource/VaultDekReadDataActorSource.php @@ -0,0 +1,13 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/VaultKekCreatedContext.php b/lib/Resource/VaultKekCreatedContext.php new file mode 100644 index 00000000..12208172 --- /dev/null +++ b/lib/Resource/VaultKekCreatedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?VaultKekCreatedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? VaultKekCreatedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/VaultKekCreatedContextActor.php b/lib/Resource/VaultKekCreatedContextActor.php new file mode 100644 index 00000000..1747b78f --- /dev/null +++ b/lib/Resource/VaultKekCreatedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/VaultKekCreatedContextGoogleAnalyticsSession.php b/lib/Resource/VaultKekCreatedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..a81762d0 --- /dev/null +++ b/lib/Resource/VaultKekCreatedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/VaultKekCreatedData.php b/lib/Resource/VaultKekCreatedData.php new file mode 100644 index 00000000..afee1da5 --- /dev/null +++ b/lib/Resource/VaultKekCreatedData.php @@ -0,0 +1,48 @@ + $this->actorId, + 'actor_source' => $this->actorSource->value, + 'actor_name' => $this->actorName, + 'key_name' => $this->keyName, + 'key_id' => $this->keyId, + ]; + } +} diff --git a/lib/Resource/VaultMetadataRead.php b/lib/Resource/VaultMetadataRead.php new file mode 100644 index 00000000..7be02b5d --- /dev/null +++ b/lib/Resource/VaultMetadataRead.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/VaultMetadataReadContext.php b/lib/Resource/VaultMetadataReadContext.php new file mode 100644 index 00000000..f851f227 --- /dev/null +++ b/lib/Resource/VaultMetadataReadContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?VaultMetadataReadContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? VaultMetadataReadContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/VaultMetadataReadContextActor.php b/lib/Resource/VaultMetadataReadContextActor.php new file mode 100644 index 00000000..f8ad1f2d --- /dev/null +++ b/lib/Resource/VaultMetadataReadContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/VaultMetadataReadContextGoogleAnalyticsSession.php b/lib/Resource/VaultMetadataReadContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..37f658e2 --- /dev/null +++ b/lib/Resource/VaultMetadataReadContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/VaultMetadataReadData.php b/lib/Resource/VaultMetadataReadData.php new file mode 100644 index 00000000..4fca215e --- /dev/null +++ b/lib/Resource/VaultMetadataReadData.php @@ -0,0 +1,44 @@ + $this->actorId, + 'actor_source' => $this->actorSource->value, + 'actor_name' => $this->actorName, + 'kv_name' => $this->kvName, + ]; + } +} diff --git a/lib/Resource/VaultNamesListed.php b/lib/Resource/VaultNamesListed.php new file mode 100644 index 00000000..65964cbd --- /dev/null +++ b/lib/Resource/VaultNamesListed.php @@ -0,0 +1,50 @@ + $this->id, + 'event' => $this->event, + 'data' => $this->data->toArray(), + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'object' => $this->object, + 'context' => $this->context?->toArray(), + ]; + } +} diff --git a/lib/Resource/VaultNamesListedContext.php b/lib/Resource/VaultNamesListedContext.php new file mode 100644 index 00000000..bdf75779 --- /dev/null +++ b/lib/Resource/VaultNamesListedContext.php @@ -0,0 +1,59 @@ +|null + */ + public ?array $googleAnalyticsSessions = null, + /** The anonymous ID from analytics. */ + public ?string $ajsAnonymousId = null, + /** The client ID associated with the event. */ + public ?string $clientId = null, + /** The actor who performed the action. */ + public ?VaultNamesListedContextActor $actor = null, + /** + * Attributes that changed from their previous values. + * @var array|null + */ + public ?array $previousAttributes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + googleAnalyticsClientId: $data['google_analytics_client_id'] ?? null, + googleAnalyticsSessions: $data['google_analytics_sessions'] ?? null, + ajsAnonymousId: $data['ajs_anonymous_id'] ?? null, + clientId: $data['client_id'] ?? null, + actor: isset($data['actor']) ? VaultNamesListedContextActor::fromArray($data['actor']) : null, + previousAttributes: $data['previous_attributes'] ?? null, + ); + } + + public function toArray(): array + { + return [ + 'google_analytics_client_id' => $this->googleAnalyticsClientId, + 'google_analytics_sessions' => $this->googleAnalyticsSessions !== null ? array_map(fn ($item) => $item->toArray(), $this->googleAnalyticsSessions) : null, + 'ajs_anonymous_id' => $this->ajsAnonymousId, + 'client_id' => $this->clientId, + 'actor' => $this->actor?->toArray(), + 'previous_attributes' => $this->previousAttributes, + ]; + } +} diff --git a/lib/Resource/VaultNamesListedContextActor.php b/lib/Resource/VaultNamesListedContextActor.php new file mode 100644 index 00000000..65686991 --- /dev/null +++ b/lib/Resource/VaultNamesListedContextActor.php @@ -0,0 +1,41 @@ + $this->id, + 'source' => $this->source->value, + 'name' => $this->name, + ]; + } +} diff --git a/lib/Resource/VaultNamesListedContextGoogleAnalyticsSession.php b/lib/Resource/VaultNamesListedContextGoogleAnalyticsSession.php new file mode 100644 index 00000000..78ba2fd2 --- /dev/null +++ b/lib/Resource/VaultNamesListedContextGoogleAnalyticsSession.php @@ -0,0 +1,40 @@ + $this->containerId, + 'sessionId' => $this->sessionId, + 'sessionNumber' => $this->sessionNumber, + ]; + } +} diff --git a/lib/Resource/VaultNamesListedData.php b/lib/Resource/VaultNamesListedData.php new file mode 100644 index 00000000..b7d7c8e4 --- /dev/null +++ b/lib/Resource/VaultNamesListedData.php @@ -0,0 +1,40 @@ + $this->actorId, + 'actor_source' => $this->actorSource->value, + 'actor_name' => $this->actorName, + ]; + } +} diff --git a/lib/Resource/VaultObject.php b/lib/Resource/VaultObject.php deleted file mode 100644 index ed189192..00000000 --- a/lib/Resource/VaultObject.php +++ /dev/null @@ -1,27 +0,0 @@ - "id", - "name" => "name", - "updated_at" => "updatedAt", - "value" => "value", - "metadata" => "metadata" - ]; -} diff --git a/lib/Resource/VerificationChallenge.php b/lib/Resource/VerificationChallenge.php deleted file mode 100644 index 796bc71e..00000000 --- a/lib/Resource/VerificationChallenge.php +++ /dev/null @@ -1,21 +0,0 @@ - "challenge", - "valid" => "valid" - ]; -} diff --git a/lib/Resource/VerifyEmailAddress.php b/lib/Resource/VerifyEmailAddress.php new file mode 100644 index 00000000..598575b9 --- /dev/null +++ b/lib/Resource/VerifyEmailAddress.php @@ -0,0 +1,32 @@ + $this->code, + ]; + } +} diff --git a/lib/Resource/VerifyEmailResponse.php b/lib/Resource/VerifyEmailResponse.php new file mode 100644 index 00000000..e74a6b1f --- /dev/null +++ b/lib/Resource/VerifyEmailResponse.php @@ -0,0 +1,32 @@ + $this->user->toArray(), + ]; + } +} diff --git a/lib/Resource/Webhook.php b/lib/Resource/Webhook.php index 90539e6f..ad186736 100644 --- a/lib/Resource/Webhook.php +++ b/lib/Resource/Webhook.php @@ -1,85 +1,38 @@ , - * created_at: string, - * updated_at: string - * } $organization Organization details for authentication events - * @property-read ?object{ - * object: 'organization_membership', - * id: string, - * user_id: string, - * organization_id: string, - * role: array{slug: string}, - * status: string, - * created_at: string, - * updated_at: string - * } $organization_membership Organization membership details for authentication events - * - * Common Properties - * @property-read string $ip_address IP address of the event - * @property-read string $user_agent User agent string of the event - * @property-read string $device_fingerprint Device fingerprint of the event + * Representation of a WorkOS webhook event. */ class Webhook { /** - * Creates a webhook object from a payload. + * Parse a webhook payload JSON string into an object. * - * @param string $payload JSON string containing webhook data - * @return static + * @param string $payload JSON string + * @return object */ - public static function constructFromPayload($payload) + public static function constructFromPayload(string $payload): object { - $jsonPayload = json_decode($payload); - $object = (object) $jsonPayload; + return (object) json_decode($payload, false); + } - return $object; + /** + * Compute an HMAC-SHA256 signature for webhook verification. + * + * @param int|string $timestamp Unix timestamp (ms) + * @param string $payload JSON payload string + * @param string $secret Webhook signing secret + * @return string Hex-encoded signature + */ + public function computeSignature(int|string $timestamp, string $payload, string $secret): string + { + $signedPayload = "{$timestamp}.{$payload}"; + return hash_hmac('sha256', $signedPayload, $secret); } } diff --git a/lib/Resource/WebhookEndpointJson.php b/lib/Resource/WebhookEndpointJson.php new file mode 100644 index 00000000..fc7d1d68 --- /dev/null +++ b/lib/Resource/WebhookEndpointJson.php @@ -0,0 +1,63 @@ + + */ + public array $events, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $createdAt, + /** An ISO 8601 timestamp. */ + public \DateTimeImmutable $updatedAt, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + object: $data['object'], + id: $data['id'], + endpointUrl: $data['endpoint_url'], + secret: $data['secret'], + status: WebhookEndpointJsonStatus::from($data['status']), + events: $data['events'], + createdAt: new \DateTimeImmutable($data['created_at']), + updatedAt: new \DateTimeImmutable($data['updated_at']), + ); + } + + public function toArray(): array + { + return [ + 'object' => $this->object, + 'id' => $this->id, + 'endpoint_url' => $this->endpointUrl, + 'secret' => $this->secret, + 'status' => $this->status->value, + 'events' => $this->events, + 'created_at' => $this->createdAt->format(\DateTimeInterface::RFC3339_EXTENDED), + 'updated_at' => $this->updatedAt->format(\DateTimeInterface::RFC3339_EXTENDED), + ]; + } +} diff --git a/lib/Resource/WebhookEndpointJsonStatus.php b/lib/Resource/WebhookEndpointJsonStatus.php new file mode 100644 index 00000000..a591cb02 --- /dev/null +++ b/lib/Resource/WebhookEndpointJsonStatus.php @@ -0,0 +1,13 @@ + */ + private array $payload; - /** - * @var string - */ - private $signature; + private string $signature; /** - * Create a new WebhookResponse instance + * Create a new WebhookResponse instance. * * @param string $type Either USER_REGISTRATION_ACTION or AUTHENTICATION_ACTION - * @param string $secret Webhook secret for signing the response + * @param string $secret Webhook secret for signing * @param string $verdict Either VERDICT_ALLOW or VERDICT_DENY - * @param string|null $errorMessage Required if verdict is VERDICT_DENY + * @param string|null $errorMessage Required when verdict is VERDICT_DENY * @return self - * @throws \InvalidArgumentException */ - public static function create($type, $secret, $verdict, ?string $errorMessage = null) + public static function create(string $type, string $secret, string $verdict, ?string $errorMessage = null): self { - if (!in_array($type, [self::USER_REGISTRATION_ACTION, self::AUTHENTICATION_ACTION])) { + if (!in_array($type, [self::USER_REGISTRATION_ACTION, self::AUTHENTICATION_ACTION], true)) { throw new \InvalidArgumentException('Invalid response type'); } - if (empty($secret)) { + if ($secret === '') { throw new \InvalidArgumentException('Secret is required'); } - if (!in_array($verdict, [self::VERDICT_ALLOW, self::VERDICT_DENY])) { + if (!in_array($verdict, [self::VERDICT_ALLOW, self::VERDICT_DENY], true)) { throw new \InvalidArgumentException('Invalid verdict'); } - if ($verdict === self::VERDICT_DENY && empty($errorMessage)) { + if ($verdict === self::VERDICT_DENY && ($errorMessage === null || $errorMessage === '')) { throw new \InvalidArgumentException('Error message is required when verdict is Deny'); } @@ -64,7 +55,7 @@ public static function create($type, $secret, $verdict, ?string $errorMessage = $payload = [ 'timestamp' => time() * 1000, - 'verdict' => $verdict + 'verdict' => $verdict, ]; if ($verdict === self::VERDICT_DENY) { @@ -75,37 +66,25 @@ public static function create($type, $secret, $verdict, ?string $errorMessage = $timestamp = $payload['timestamp']; $payloadString = json_encode($payload); - $instance->signature = (new Webhook())->computeSignature($timestamp, $payloadString, $secret); + $instance->signature = (new Webhook())->computeSignature($timestamp, (string) $payloadString, $secret); return $instance; } /** - * Get the response as an array - * - * @return array + * @return array */ - public function toArray() + public function toArray(): array { - $response = [ + return [ 'object' => $this->object, - 'payload' => $this->payload + 'payload' => $this->payload, + 'signature' => $this->signature, ]; - - if ($this->signature) { - $response['signature'] = $this->signature; - } - - return $response; } - /** - * Get the response as a JSON string - * - * @return string - */ - public function toJson() + public function toJson(): string { - return json_encode($this->toArray()); + return (string) json_encode($this->toArray()); } } diff --git a/lib/Resource/WebhooksOrder.php b/lib/Resource/WebhooksOrder.php new file mode 100644 index 00000000..978d76ae --- /dev/null +++ b/lib/Resource/WebhooksOrder.php @@ -0,0 +1,14 @@ +|null + */ + public ?array $scopes = null, + ) { + } + + public static function fromArray(array $data): self + { + return new self( + organizationId: $data['organization_id'], + userId: $data['user_id'] ?? null, + scopes: isset($data['scopes']) ? array_map(fn ($item) => WidgetSessionTokenScopes::from($item), $data['scopes']) : null, + ); + } + + public function toArray(): array + { + return [ + 'organization_id' => $this->organizationId, + 'user_id' => $this->userId, + 'scopes' => $this->scopes !== null ? array_map(fn ($item) => $item->value, $this->scopes) : null, + ]; + } +} diff --git a/lib/Resource/WidgetSessionTokenResponse.php b/lib/Resource/WidgetSessionTokenResponse.php new file mode 100644 index 00000000..c1765f08 --- /dev/null +++ b/lib/Resource/WidgetSessionTokenResponse.php @@ -0,0 +1,32 @@ + $this->token, + ]; + } +} diff --git a/lib/Resource/WidgetSessionTokenScopes.php b/lib/Resource/WidgetSessionTokenScopes.php new file mode 100644 index 00000000..fd1767a8 --- /dev/null +++ b/lib/Resource/WidgetSessionTokenScopes.php @@ -0,0 +1,17 @@ + "token" - ]; -} diff --git a/lib/SSO.php b/lib/SSO.php deleted file mode 100644 index 02d85353..00000000 --- a/lib/SSO.php +++ /dev/null @@ -1,252 +0,0 @@ - WorkOS::getClientId(), - "response_type" => "code" - ]; - - if ($domain) { - $params["domain"] = $domain; - } - - if ($redirectUri) { - $params["redirect_uri"] = $redirectUri; - } - - if (null !== $state && !empty($state)) { - $params["state"] = \json_encode($state); - } - - if ($provider) { - $params["provider"] = $provider; - } - - if ($connection) { - $params["connection"] = $connection; - } - - if ($organization) { - $params["organization"] = $organization; - } - - if ($domainHint) { - $params["domain_hint"] = $domainHint; - } - - if ($loginHint) { - $params["login_hint"] = $loginHint; - } - - return Client::generateUrl($authorizationPath, $params); - } - - /** - * Verify that SSO has been completed successfully and retrieve the identity of the user. - * - * @param string $code Code returned by WorkOS on completion of OAuth 2.0 flow - * - * @throws Exception\WorkOSException - * - * @return Resource\ProfileAndToken - */ - public function getProfileAndToken($code) - { - $profilePath = "sso/token"; - - $params = [ - "client_id" => WorkOS::getClientId(), - "client_secret" => WorkOS::getApikey(), - "code" => $code, - "grant_type" => "authorization_code" - ]; - - $response = Client::request(Client::METHOD_POST, $profilePath, null, $params); - - return Resource\ProfileAndToken::constructFromResponse($response); - } - - /** - * Verify that SSO has been completed successfully and retrieve the identity of the user. - * - * @param string $accessToken, the token used to authenticate the API call - * - * @throws Exception\GenericException - * - * @return Resource\Profile - */ - public function getProfile($accessToken) - { - $getProfilePath = "sso/profile"; - - $params = [ - "access_token" => $accessToken - ]; - - $method = Client::METHOD_GET; - - $url = "https://api.workos.com/sso/profile"; - - $requestHeaders = ["Authorization: Bearer " . $accessToken]; - - list($result) = Client::requestClient()->request( - $method, - $url, - $requestHeaders, - null - ); - - $decodedResponse = json_decode($result, true); - - $profile = Resource\Profile::constructFromResponse($decodedResponse); - - return $profile->json(); - } - - /** - * Delete a Connection. - * - * @param string $connection Connection ID - * - * @throws Exception\WorkOSException - * - * @return Resource\Response - */ - public function deleteConnection($connection) - { - $connectionPath = "connections/{$connection}"; - - $response = Client::request( - Client::METHOD_DELETE, - $connectionPath, - null, - null, - true - ); - - return $response; - } - - /** - * Get a Connection. - * - * @param string $connection Connection ID - * - * @throws Exception\WorkOSException - * - * @return Resource\Connection - */ - public function getConnection($connection) - { - $connectionPath = "connections/{$connection}"; - - $response = Client::request( - Client::METHOD_GET, - $connectionPath, - null, - null, - true - ); - - return Resource\Connection::constructFromResponse($response); - } - - public const DEFAULT_PAGE_SIZE = 10; - - /** - * List Connections. - * - * @param null|string $domain Domain of a Connection - * @param null|string $connectionType Authentication service provider descriptor - * @param null|string $organizationId Organization ID of the Connection(s) - * @param int $limit Maximum number of records to return - * @param null|string $before Connection ID to look before - * @param null|string $after Connection ID to look after - * @param Resource\Order $order The Order in which to paginate records - * - * @return Resource\PaginatedResource A paginated resource containing before/after cursors and connections array. - * Supports: [$before, $after, $connections] = $result, ["connections" => $connections] = $result, $result->connections - * - * @throws Exception\WorkOSException - */ - public function listConnections( - ?string $domain = null, - ?string $connectionType = null, - ?string $organizationId = null, - $limit = self::DEFAULT_PAGE_SIZE, - ?string $before = null, - ?string $after = null, - ?string $order = null - ) { - $connectionsPath = "connections"; - $params = [ - "limit" => $limit, - "before" => $before, - "after" => $after, - "domain" => $domain, - "connection_type" => $connectionType, - "organization_id" => $organizationId, - "order" => $order - ]; - - $response = Client::request( - Client::METHOD_GET, - $connectionsPath, - null, - $params, - true - ); - - return Resource\PaginatedResource::constructFromResponse($response, Resource\Connection::class, 'connections'); - } -} diff --git a/lib/Service/AdminPortal.php b/lib/Service/AdminPortal.php new file mode 100644 index 00000000..77a07e64 --- /dev/null +++ b/lib/Service/AdminPortal.php @@ -0,0 +1,63 @@ +|null $adminEmails The email addresses of the IT admins to grant access to the Admin Portal for the given organization. Accepts up to 20 emails. + * @return \WorkOS\Resource\PortalLinkResponse + */ + public function generateLink( + string $organization, + ?string $returnUrl = null, + ?string $successUrl = null, + ?\WorkOS\Resource\GenerateLinkIntent $intent = null, + ?\WorkOS\Resource\IntentOptions $intentOptions = null, + ?array $adminEmails = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\PortalLinkResponse { + $body = array_filter([ + 'return_url' => $returnUrl, + 'success_url' => $successUrl, + 'organization' => $organization, + 'intent' => $intent?->value, + 'intent_options' => $intentOptions, + 'admin_emails' => $adminEmails, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'POST', + path: 'portal/generate_link', + body: $body, + options: $options, + ); + return PortalLinkResponse::fromArray($response); + } +} diff --git a/lib/Service/ApiKeys.php b/lib/Service/ApiKeys.php new file mode 100644 index 00000000..d9114323 --- /dev/null +++ b/lib/Service/ApiKeys.php @@ -0,0 +1,122 @@ + $value, + ]; + $response = $this->client->request( + method: 'POST', + path: 'api_keys/validations', + body: $body, + options: $options, + ); + return ApiKeyValidationResponse::fromArray($response); + } + + /** + * Delete an API key + * + * Permanently deletes an API key. This action cannot be undone. Once deleted, any requests using this API key will fail authentication. + * @param string $id The unique ID of the API key. + * @return void + */ + public function deleteApiKey( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): void { + $this->client->request( + method: 'DELETE', + path: "api_keys/{$id}", + options: $options, + ); + } + + /** + * List API keys for an organization + * + * Get a list of all API keys for an organization. + * @param string $organizationId Unique identifier of the Organization. + * @param string|null $before An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. + * @param string|null $after An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. + * @param int|null $limit Upper limit on the number of objects to return, between `1` and `100`. Defaults to 10. + * @param \WorkOS\Resource\EventsOrder|null $order Order the results by the creation time. Defaults to "desc". + * @return \WorkOS\PaginatedResponse<\WorkOS\Resource\ApiKey> + */ + public function listOrganizationApiKeys( + string $organizationId, + ?string $before = null, + ?string $after = null, + ?int $limit = null, + ?\WorkOS\Resource\EventsOrder $order = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\PaginatedResponse { + $query = array_filter([ + 'before' => $before, + 'after' => $after, + 'limit' => $limit, + 'order' => $order?->value, + ], fn ($v) => $v !== null); + return $this->client->requestPage( + method: 'GET', + path: "organizations/{$organizationId}/api_keys", + query: $query, + modelClass: ApiKey::class, + options: $options, + ); + } + + /** + * Create an API key for an organization + * + * Create a new API key for an organization. + * @param string $organizationId Unique identifier of the Organization. + * @param string $name The name for the API key. + * @param array|null $permissions The permission slugs to assign to the API key. + * @return \WorkOS\Resource\ApiKeyWithValue + */ + public function createOrganizationApiKeys( + string $organizationId, + string $name, + ?array $permissions = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\ApiKeyWithValue { + $body = array_filter([ + 'name' => $name, + 'permissions' => $permissions, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'POST', + path: "organizations/{$organizationId}/api_keys", + body: $body, + options: $options, + ); + return ApiKeyWithValue::fromArray($response); + } +} diff --git a/lib/Service/AuditLogs.php b/lib/Service/AuditLogs.php new file mode 100644 index 00000000..0ace28af --- /dev/null +++ b/lib/Service/AuditLogs.php @@ -0,0 +1,257 @@ +client->request( + method: 'GET', + path: "organizations/{$id}/audit_logs_retention", + options: $options, + ); + return AuditLogsRetentionJson::fromArray($response); + } + + /** + * Set Retention + * + * Set the event retention period for the given Organization. + * @param string $id Unique identifier of the Organization. + * @param int $retentionPeriodInDays The number of days Audit Log events will be retained. Valid values are `30` and `365`. + * @return \WorkOS\Resource\AuditLogsRetentionJson + */ + public function updateOrganizationAuditLogsRetention( + string $id, + int $retentionPeriodInDays, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\AuditLogsRetentionJson { + $body = [ + 'retention_period_in_days' => $retentionPeriodInDays, + ]; + $response = $this->client->request( + method: 'PUT', + path: "organizations/{$id}/audit_logs_retention", + body: $body, + options: $options, + ); + return AuditLogsRetentionJson::fromArray($response); + } + + /** + * List Actions + * + * Get a list of all Audit Log actions in the current environment. + * @param string|null $before An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. + * @param string|null $after An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. + * @param int|null $limit Upper limit on the number of objects to return, between `1` and `100`. Defaults to 10. + * @param \WorkOS\Resource\EventsOrder|null $order Order the results by the creation time. Defaults to "desc". + * @return \WorkOS\PaginatedResponse<\WorkOS\Resource\AuditLogActionJson> + */ + public function listActions( + ?string $before = null, + ?string $after = null, + ?int $limit = null, + ?\WorkOS\Resource\EventsOrder $order = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\PaginatedResponse { + $query = array_filter([ + 'before' => $before, + 'after' => $after, + 'limit' => $limit, + 'order' => $order?->value, + ], fn ($v) => $v !== null); + return $this->client->requestPage( + method: 'GET', + path: 'audit_logs/actions', + query: $query, + modelClass: AuditLogActionJson::class, + options: $options, + ); + } + + /** + * List Schemas + * + * Get a list of all schemas for the Audit Logs action identified by `:name`. + * @param string $actionName The name of the Audit Log action. + * @param string|null $before An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. + * @param string|null $after An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. + * @param int|null $limit Upper limit on the number of objects to return, between `1` and `100`. Defaults to 10. + * @param \WorkOS\Resource\EventsOrder|null $order Order the results by the creation time. Defaults to "desc". + * @return \WorkOS\PaginatedResponse<\WorkOS\Resource\AuditLogSchemaJson> + */ + public function listActionSchemas( + string $actionName, + ?string $before = null, + ?string $after = null, + ?int $limit = null, + ?\WorkOS\Resource\EventsOrder $order = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\PaginatedResponse { + $query = array_filter([ + 'before' => $before, + 'after' => $after, + 'limit' => $limit, + 'order' => $order?->value, + ], fn ($v) => $v !== null); + return $this->client->requestPage( + method: 'GET', + path: "audit_logs/actions/{$actionName}/schemas", + query: $query, + modelClass: AuditLogSchemaJson::class, + options: $options, + ); + } + + /** + * Create Schema + * + * Creates a new Audit Log schema used to validate the payload of incoming Audit Log Events. If the `action` does not exist, it will also be created. + * @param string $actionName The name of the Audit Log action. + * @param \WorkOS\Resource\AuditLogSchemaActor|null $actor The metadata schema for the actor. + * @param array<\WorkOS\Resource\AuditLogSchemaTarget> $targets The list of targets for the schema. + * @param array|null $metadata Optional JSON schema for event metadata. + * @return \WorkOS\Resource\AuditLogSchemaJson + */ + public function createSchema( + string $actionName, + array $targets, + ?\WorkOS\Resource\AuditLogSchemaActor $actor = null, + ?array $metadata = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\AuditLogSchemaJson { + $body = array_filter([ + 'actor' => $actor, + 'targets' => $targets, + 'metadata' => $metadata, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'POST', + path: "audit_logs/actions/{$actionName}/schemas", + body: $body, + options: $options, + ); + return AuditLogSchemaJson::fromArray($response); + } + + /** + * Create Event + * + * Create an Audit Log Event. + * + * This API supports idempotency which guarantees that performing the same operation multiple times will have the same result as if the operation were performed only once. This is handy in situations where you may need to retry a request due to a failure or prevent accidental duplicate requests from creating more than one resource. + * + * To achieve idempotency, you can add `Idempotency-Key` request header to a Create Event request with a unique string as the value. Each subsequent request matching this unique string will return the same response. We suggest using [v4 UUIDs](https://en.wikipedia.org/wiki/Universally_unique_identifier) for idempotency keys to avoid collisions. + * + * Idempotency keys expire after 24 hours. The API will generate a new response if you submit a request with an expired key. + * @param string $organizationId The unique ID of the Organization. + * @param \WorkOS\Resource\AuditLogEvent $event The audit log event to create. + * @return \WorkOS\Resource\AuditLogEventCreateResponse + */ + public function createEvent( + string $organizationId, + \WorkOS\Resource\AuditLogEvent $event, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\AuditLogEventCreateResponse { + $body = [ + 'organization_id' => $organizationId, + 'event' => $event, + ]; + $response = $this->client->request( + method: 'POST', + path: 'audit_logs/events', + body: $body, + options: $options, + ); + return AuditLogEventCreateResponse::fromArray($response); + } + + /** + * Create Export + * + * Create an Audit Log Export. Exports are scoped to a single organization within a specified date range. + * @param string $organizationId The unique ID of the Organization. + * @param string $rangeStart ISO-8601 value for start of the export range. + * @param string $rangeEnd ISO-8601 value for end of the export range. + * @param array|null $actions List of actions to filter against. + * @param array|null $actors (deprecated) Deprecated. Use `actor_names` instead. + * @param array|null $actorNames List of actor names to filter against. + * @param array|null $actorIds List of actor IDs to filter against. + * @param array|null $targets List of target types to filter against. + * @return \WorkOS\Resource\AuditLogExportJson + */ + public function createExport( + string $organizationId, + string $rangeStart, + string $rangeEnd, + ?array $actions = null, + ?array $actors = null, + ?array $actorNames = null, + ?array $actorIds = null, + ?array $targets = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\AuditLogExportJson { + $body = array_filter([ + 'organization_id' => $organizationId, + 'range_start' => $rangeStart, + 'range_end' => $rangeEnd, + 'actions' => $actions, + 'actors' => $actors, + 'actor_names' => $actorNames, + 'actor_ids' => $actorIds, + 'targets' => $targets, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'POST', + path: 'audit_logs/exports', + body: $body, + options: $options, + ); + return AuditLogExportJson::fromArray($response); + } + + /** + * Get Export + * + * Get an Audit Log Export. The URL will expire after 10 minutes. If the export is needed again at a later time, refetching the export will regenerate the URL. + * @param string $auditLogExportId The unique ID of the Audit Log Export. + * @return \WorkOS\Resource\AuditLogExportJson + */ + public function getExport( + string $auditLogExportId, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\AuditLogExportJson { + $response = $this->client->request( + method: 'GET', + path: "audit_logs/exports/{$auditLogExportId}", + options: $options, + ); + return AuditLogExportJson::fromArray($response); + } +} diff --git a/lib/Service/Authorization.php b/lib/Service/Authorization.php new file mode 100644 index 00000000..5602806b --- /dev/null +++ b/lib/Service/Authorization.php @@ -0,0 +1,1052 @@ + $permissionSlug, + 'resource_id' => $resourceId, + 'resource_external_id' => $resourceExternalId, + 'resource_type_slug' => $resourceTypeSlug, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'POST', + path: "authorization/organization_memberships/{$organizationMembershipId}/check", + body: $body, + options: $options, + ); + return AuthorizationCheck::fromArray($response); + } + + /** + * List resources for organization membership + * + * Returns all child resources of a parent resource where the organization membership has a specific permission. This is useful for resource discovery—answering "What projects can this user access in this workspace?" + * + * You must provide either `parent_resource_id` or both `parent_resource_external_id` and `parent_resource_type_slug` to identify the parent resource. + * @param string $organizationMembershipId The ID of the organization membership. + * @param string|null $before An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `before="obj_123"` to fetch a new batch of objects before `"obj_123"`. + * @param string|null $after An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `after="obj_123"` to fetch a new batch of objects after `"obj_123"`. + * @param int|null $limit Upper limit on the number of objects to return, between `1` and `100`. Defaults to 10. + * @param \WorkOS\Resource\EventsOrder|null $order Order the results by the creation time. Supported values are `"asc"` (ascending), `"desc"` (descending), and `"normal"` (descending with reversed cursor semantics where `before` fetches older records and `after` fetches newer records). Defaults to descending. Defaults to "desc". + * @param string $permissionSlug The permission slug to filter by. Only child resources where the organization membership has this permission are returned. + * @param string|null $parentResourceId The WorkOS ID of the parent resource. Provide this or both `parent_resource_external_id` and `parent_resource_type_slug`, but not both. + * @param string|null $parentResourceTypeSlug The slug of the parent resource type. Must be provided together with `parent_resource_external_id`. + * @param string|null $parentResourceExternalId The application-specific external identifier of the parent resource. Must be provided together with `parent_resource_type_slug`. + * @return \WorkOS\PaginatedResponse<\WorkOS\Resource\AuthorizationResource> + */ + public function listOrganizationMembershipResources( + string $organizationMembershipId, + string $permissionSlug, + ?string $before = null, + ?string $after = null, + ?int $limit = null, + ?\WorkOS\Resource\EventsOrder $order = null, + ?string $parentResourceId = null, + ?string $parentResourceTypeSlug = null, + ?string $parentResourceExternalId = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\PaginatedResponse { + $query = array_filter([ + 'before' => $before, + 'after' => $after, + 'limit' => $limit, + 'order' => $order?->value, + 'permission_slug' => $permissionSlug, + 'parent_resource_id' => $parentResourceId, + 'parent_resource_type_slug' => $parentResourceTypeSlug, + 'parent_resource_external_id' => $parentResourceExternalId, + ], fn ($v) => $v !== null); + return $this->client->requestPage( + method: 'GET', + path: "authorization/organization_memberships/{$organizationMembershipId}/resources", + query: $query, + modelClass: AuthorizationResource::class, + options: $options, + ); + } + + /** + * List role assignments + * + * List all role assignments for an organization membership. This returns all roles that have been assigned to the user on resources, including organization-level and sub-resource roles. + * @param string $organizationMembershipId The ID of the organization membership. + * @param string|null $before An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `before="obj_123"` to fetch a new batch of objects before `"obj_123"`. + * @param string|null $after An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `after="obj_123"` to fetch a new batch of objects after `"obj_123"`. + * @param int|null $limit Upper limit on the number of objects to return, between `1` and `100`. Defaults to 10. + * @param \WorkOS\Resource\EventsOrder|null $order Order the results by the creation time. Supported values are `"asc"` (ascending), `"desc"` (descending), and `"normal"` (descending with reversed cursor semantics where `before` fetches older records and `after` fetches newer records). Defaults to descending. Defaults to "desc". + * @return \WorkOS\PaginatedResponse<\WorkOS\Resource\RoleAssignment> + */ + public function listOrganizationMembershipRoleAssignments( + string $organizationMembershipId, + ?string $before = null, + ?string $after = null, + ?int $limit = null, + ?\WorkOS\Resource\EventsOrder $order = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\PaginatedResponse { + $query = array_filter([ + 'before' => $before, + 'after' => $after, + 'limit' => $limit, + 'order' => $order?->value, + ], fn ($v) => $v !== null); + return $this->client->requestPage( + method: 'GET', + path: "authorization/organization_memberships/{$organizationMembershipId}/role_assignments", + query: $query, + modelClass: RoleAssignment::class, + options: $options, + ); + } + + /** + * Assign a role + * + * Assign a role to an organization membership on a specific resource. + * @param string $organizationMembershipId The ID of the organization membership. + * @param string $roleSlug The slug of the role to assign. + * @param string|null $resourceId The ID of the resource. Use either this or `resource_external_id` and `resource_type_slug`. + * @param string|null $resourceExternalId The external ID of the resource. Requires `resource_type_slug`. + * @param string|null $resourceTypeSlug The resource type slug. Required with `resource_external_id`. + * @return \WorkOS\Resource\RoleAssignment + */ + public function assignRole( + string $organizationMembershipId, + string $roleSlug, + ?string $resourceId = null, + ?string $resourceExternalId = null, + ?string $resourceTypeSlug = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\RoleAssignment { + $body = array_filter([ + 'role_slug' => $roleSlug, + 'resource_id' => $resourceId, + 'resource_external_id' => $resourceExternalId, + 'resource_type_slug' => $resourceTypeSlug, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'POST', + path: "authorization/organization_memberships/{$organizationMembershipId}/role_assignments", + body: $body, + options: $options, + ); + return RoleAssignment::fromArray($response); + } + + /** + * Remove a role assignment + * + * Remove a role assignment by role slug and resource. + * @param string $organizationMembershipId The ID of the organization membership. + * @param string $roleSlug The slug of the role to remove. + * @param string|null $resourceId The ID of the resource. Use either this or `resource_external_id` and `resource_type_slug`. + * @param string|null $resourceExternalId The external ID of the resource. Requires `resource_type_slug`. + * @param string|null $resourceTypeSlug The resource type slug. Required with `resource_external_id`. + * @return void + */ + public function removeRole( + string $organizationMembershipId, + string $roleSlug, + ?string $resourceId = null, + ?string $resourceExternalId = null, + ?string $resourceTypeSlug = null, + ?\WorkOS\RequestOptions $options = null, + ): void { + $body = array_filter([ + 'role_slug' => $roleSlug, + 'resource_id' => $resourceId, + 'resource_external_id' => $resourceExternalId, + 'resource_type_slug' => $resourceTypeSlug, + ], fn ($v) => $v !== null); + $this->client->request( + method: 'DELETE', + path: "authorization/organization_memberships/{$organizationMembershipId}/role_assignments", + body: $body, + options: $options, + ); + } + + /** + * Remove a role assignment by ID + * + * Remove a role assignment using its ID. + * @param string $organizationMembershipId The ID of the organization membership. + * @param string $roleAssignmentId The ID of the role assignment to remove. + * @return void + */ + public function deleteOrganizationMembershipRoleAssignment( + string $organizationMembershipId, + string $roleAssignmentId, + ?\WorkOS\RequestOptions $options = null, + ): void { + $this->client->request( + method: 'DELETE', + path: "authorization/organization_memberships/{$organizationMembershipId}/role_assignments/{$roleAssignmentId}", + options: $options, + ); + } + + /** + * List organization roles + * + * Get a list of all roles that apply to an organization. This includes both environment roles and organization-specific roles, returned in priority order. + * @param string $organizationId The ID of the organization. + * @return \WorkOS\Resource\RoleList + */ + public function listOrganizationRoles( + string $organizationId, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\RoleList { + $response = $this->client->request( + method: 'GET', + path: "authorization/organizations/{$organizationId}/roles", + options: $options, + ); + return RoleList::fromArray($response); + } + + /** + * Create a custom organization role + * + * Create a new custom organization role. When slug is omitted, it is auto-generated from the role name. + * @param string $organizationId The ID of the organization. + * @param string|null $slug A unique identifier for the role within the organization. When provided, must begin with 'org-' and contain only lowercase letters, numbers, hyphens, and underscores. When omitted, a slug is auto-generated from the role name and a random suffix. + * @param string $name A descriptive name for the role. + * @param string|null $description An optional description of the role's purpose. + * @param string|null $resourceTypeSlug The slug of the resource type the role is scoped to. + * @return \WorkOS\Resource\Role + */ + public function createOrganizationRole( + string $organizationId, + string $name, + ?string $slug = null, + ?string $description = null, + ?string $resourceTypeSlug = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\Role { + $body = array_filter([ + 'slug' => $slug, + 'name' => $name, + 'description' => $description, + 'resource_type_slug' => $resourceTypeSlug, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'POST', + path: "authorization/organizations/{$organizationId}/roles", + body: $body, + options: $options, + ); + return Role::fromArray($response); + } + + /** + * Get an organization role + * + * Retrieve a role that applies to an organization by its slug. This can return either an environment role or an organization-specific role. + * @param string $organizationId The ID of the organization. + * @param string $slug The slug of the role. + * @return \WorkOS\Resource\Role + */ + public function getOrganizationRole( + string $organizationId, + string $slug, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\Role { + $response = $this->client->request( + method: 'GET', + path: "authorization/organizations/{$organizationId}/roles/{$slug}", + options: $options, + ); + return Role::fromArray($response); + } + + /** + * Update an organization role + * + * Update an existing custom organization role. Only the fields provided in the request body will be updated. + * @param string $organizationId The ID of the organization. + * @param string $slug The slug of the role. + * @param string|null $name A descriptive name for the role. + * @param string|null $description An optional description of the role's purpose. + * @return \WorkOS\Resource\Role + */ + public function updateOrganizationRole( + string $organizationId, + string $slug, + ?string $name = null, + ?string $description = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\Role { + $body = array_filter([ + 'name' => $name, + 'description' => $description, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'PATCH', + path: "authorization/organizations/{$organizationId}/roles/{$slug}", + body: $body, + options: $options, + ); + return Role::fromArray($response); + } + + /** + * Delete a custom organization role + * + * Delete an existing custom organization role. + * @param string $organizationId The ID of the organization. + * @param string $slug The slug of the role. + * @return void + */ + public function deleteOrganizationRole( + string $organizationId, + string $slug, + ?\WorkOS\RequestOptions $options = null, + ): void { + $this->client->request( + method: 'DELETE', + path: "authorization/organizations/{$organizationId}/roles/{$slug}", + options: $options, + ); + } + + /** + * Add a permission to an organization role + * + * Add a single permission to an organization role. If the permission is already assigned to the role, this operation has no effect. + * @param string $organizationId The ID of the organization. + * @param string $slug The slug of the role. + * @param string $bodySlug The slug of the permission to add to the role. + * @return \WorkOS\Resource\Role + */ + public function createRolePermissions( + string $organizationId, + string $slug, + string $bodySlug, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\Role { + $body = [ + 'slug' => $bodySlug, + ]; + $response = $this->client->request( + method: 'POST', + path: "authorization/organizations/{$organizationId}/roles/{$slug}/permissions", + body: $body, + options: $options, + ); + return Role::fromArray($response); + } + + /** + * Set permissions for a role + * + * Replace all permissions on a role with the provided list. + * @param string $organizationId The ID of the organization. + * @param string $slug The slug of the role. + * @param array $permissions The permission slugs to assign to the role. + * @return \WorkOS\Resource\Role + */ + public function updateRolePermissions( + string $organizationId, + string $slug, + array $permissions, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\Role { + $body = [ + 'permissions' => $permissions, + ]; + $response = $this->client->request( + method: 'PUT', + path: "authorization/organizations/{$organizationId}/roles/{$slug}/permissions", + body: $body, + options: $options, + ); + return Role::fromArray($response); + } + + /** + * Remove a permission from an organization role + * + * Remove a single permission from an organization role by its slug. + * @param string $organizationId The ID of the organization. + * @param string $slug The slug of the role. + * @param string $permissionSlug The slug of the permission to remove. + * @return void + */ + public function deleteRolePermission( + string $organizationId, + string $slug, + string $permissionSlug, + ?\WorkOS\RequestOptions $options = null, + ): void { + $this->client->request( + method: 'DELETE', + path: "authorization/organizations/{$organizationId}/roles/{$slug}/permissions/{$permissionSlug}", + options: $options, + ); + } + + /** + * Get a resource by external ID + * + * Retrieve the details of an authorization resource by its external ID, organization, and resource type. This is useful when you only have the external ID from your system and need to fetch the full resource details. + * @param string $organizationId The ID of the organization that owns the resource. + * @param string $resourceTypeSlug The slug of the resource type. + * @param string $externalId An identifier you provide to reference the resource in your system. + * @return \WorkOS\Resource\AuthorizationResource + */ + public function getOrganizationResource( + string $organizationId, + string $resourceTypeSlug, + string $externalId, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\AuthorizationResource { + $response = $this->client->request( + method: 'GET', + path: "authorization/organizations/{$organizationId}/resources/{$resourceTypeSlug}/{$externalId}", + options: $options, + ); + return AuthorizationResource::fromArray($response); + } + + /** + * Update a resource by external ID + * + * Update an existing authorization resource using its external ID. + * @param string $organizationId The ID of the organization that owns the resource. + * @param string $resourceTypeSlug The slug of the resource type. + * @param string $externalId An identifier you provide to reference the resource in your system. + * @param string|null $name A display name for the resource. + * @param string|null $description An optional description of the resource. + * @param string|null $parentResourceId The ID of the parent resource. + * @param string|null $parentResourceExternalId The external ID of the parent resource. + * @param string|null $parentResourceTypeSlug The resource type slug of the parent resource. + * @return \WorkOS\Resource\AuthorizationResource + */ + public function updateOrganizationResource( + string $organizationId, + string $resourceTypeSlug, + string $externalId, + ?string $name = null, + ?string $description = null, + ?string $parentResourceId = null, + ?string $parentResourceExternalId = null, + ?string $parentResourceTypeSlug = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\AuthorizationResource { + $body = array_filter([ + 'name' => $name, + 'description' => $description, + 'parent_resource_id' => $parentResourceId, + 'parent_resource_external_id' => $parentResourceExternalId, + 'parent_resource_type_slug' => $parentResourceTypeSlug, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'PATCH', + path: "authorization/organizations/{$organizationId}/resources/{$resourceTypeSlug}/{$externalId}", + body: $body, + options: $options, + ); + return AuthorizationResource::fromArray($response); + } + + /** + * Delete an authorization resource by external ID + * + * Delete an authorization resource by organization, resource type, and external ID. This also deletes all descendant resources. + * @param string $organizationId The ID of the organization that owns the resource. + * @param string $resourceTypeSlug The slug of the resource type. + * @param string $externalId An identifier you provide to reference the resource in your system. + * @param bool|null $cascadeDelete If true, deletes all descendant resources and role assignments. If not set and the resource has children or assignments, the request will fail. Defaults to false. + * @return void + */ + public function deleteOrganizationResource( + string $organizationId, + string $resourceTypeSlug, + string $externalId, + ?bool $cascadeDelete = null, + ?\WorkOS\RequestOptions $options = null, + ): void { + $query = array_filter([ + 'cascade_delete' => $cascadeDelete, + ], fn ($v) => $v !== null); + $this->client->request( + method: 'DELETE', + path: "authorization/organizations/{$organizationId}/resources/{$resourceTypeSlug}/{$externalId}", + query: $query, + options: $options, + ); + } + + /** + * List memberships for a resource by external ID + * + * Returns all organization memberships that have a specific permission on a resource, using the resource's external ID. This is useful for answering "Who can access this resource?" when you only have the external ID. + * @param string $organizationId The ID of the organization that owns the resource. + * @param string $resourceTypeSlug The slug of the resource type this resource belongs to. + * @param string $externalId An identifier you provide to reference the resource in your system. + * @param string|null $before An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `before="obj_123"` to fetch a new batch of objects before `"obj_123"`. + * @param string|null $after An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `after="obj_123"` to fetch a new batch of objects after `"obj_123"`. + * @param int|null $limit Upper limit on the number of objects to return, between `1` and `100`. Defaults to 10. + * @param \WorkOS\Resource\EventsOrder|null $order Order the results by the creation time. Supported values are `"asc"` (ascending), `"desc"` (descending), and `"normal"` (descending with reversed cursor semantics where `before` fetches older records and `after` fetches newer records). Defaults to descending. Defaults to "desc". + * @param string $permissionSlug The permission slug to filter by. Only users with this permission on the resource are returned. + * @param \WorkOS\Resource\AuthorizationAssignment|null $assignment Filter by assignment type. Use "direct" for direct assignments only, or "indirect" to include inherited assignments. + * @return \WorkOS\PaginatedResponse<\WorkOS\Resource\UserOrganizationMembershipBaseListData> + */ + public function listResourceOrganizationMemberships( + string $organizationId, + string $resourceTypeSlug, + string $externalId, + string $permissionSlug, + ?string $before = null, + ?string $after = null, + ?int $limit = null, + ?\WorkOS\Resource\EventsOrder $order = null, + ?\WorkOS\Resource\AuthorizationAssignment $assignment = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\PaginatedResponse { + $query = array_filter([ + 'before' => $before, + 'after' => $after, + 'limit' => $limit, + 'order' => $order?->value, + 'permission_slug' => $permissionSlug, + 'assignment' => $assignment?->value, + ], fn ($v) => $v !== null); + return $this->client->requestPage( + method: 'GET', + path: "authorization/organizations/{$organizationId}/resources/{$resourceTypeSlug}/{$externalId}/organization_memberships", + query: $query, + modelClass: UserOrganizationMembershipBaseListData::class, + options: $options, + ); + } + + /** + * List resources + * + * Get a paginated list of authorization resources. + * @param string|null $before An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `before="obj_123"` to fetch a new batch of objects before `"obj_123"`. + * @param string|null $after An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `after="obj_123"` to fetch a new batch of objects after `"obj_123"`. + * @param int|null $limit Upper limit on the number of objects to return, between `1` and `100`. Defaults to 10. + * @param \WorkOS\Resource\EventsOrder|null $order Order the results by the creation time. Supported values are `"asc"` (ascending), `"desc"` (descending), and `"normal"` (descending with reversed cursor semantics where `before` fetches older records and `after` fetches newer records). Defaults to descending. Defaults to "desc". + * @param string|null $organizationId Filter resources by organization ID. + * @param string|null $resourceTypeSlug Filter resources by resource type slug. + * @param string|null $parentResourceId Filter resources by parent resource ID. + * @param string|null $parentResourceTypeSlug Filter resources by parent resource type slug. + * @param string|null $parentExternalId Filter resources by parent external ID. + * @param string|null $search Search resources by name. + * @return \WorkOS\PaginatedResponse<\WorkOS\Resource\AuthorizationResource> + */ + public function listResources( + ?string $before = null, + ?string $after = null, + ?int $limit = null, + ?\WorkOS\Resource\EventsOrder $order = null, + ?string $organizationId = null, + ?string $resourceTypeSlug = null, + ?string $parentResourceId = null, + ?string $parentResourceTypeSlug = null, + ?string $parentExternalId = null, + ?string $search = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\PaginatedResponse { + $query = array_filter([ + 'before' => $before, + 'after' => $after, + 'limit' => $limit, + 'order' => $order?->value, + 'organization_id' => $organizationId, + 'resource_type_slug' => $resourceTypeSlug, + 'parent_resource_id' => $parentResourceId, + 'parent_resource_type_slug' => $parentResourceTypeSlug, + 'parent_external_id' => $parentExternalId, + 'search' => $search, + ], fn ($v) => $v !== null); + return $this->client->requestPage( + method: 'GET', + path: 'authorization/resources', + query: $query, + modelClass: AuthorizationResource::class, + options: $options, + ); + } + + /** + * Create an authorization resource + * + * Create a new authorization resource. + * @param string $externalId An external identifier for the resource. + * @param string $name A display name for the resource. + * @param string|null $description An optional description of the resource. + * @param string $resourceTypeSlug The slug of the resource type. + * @param string $organizationId The ID of the organization this resource belongs to. + * @param string|null $parentResourceId The ID of the parent resource. + * @param string|null $parentResourceExternalId The external ID of the parent resource. + * @param string|null $parentResourceTypeSlug The resource type slug of the parent resource. + * @return \WorkOS\Resource\AuthorizationResource + */ + public function createResource( + string $externalId, + string $name, + string $resourceTypeSlug, + string $organizationId, + ?string $description = null, + ?string $parentResourceId = null, + ?string $parentResourceExternalId = null, + ?string $parentResourceTypeSlug = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\AuthorizationResource { + $body = array_filter([ + 'external_id' => $externalId, + 'name' => $name, + 'description' => $description, + 'resource_type_slug' => $resourceTypeSlug, + 'organization_id' => $organizationId, + 'parent_resource_id' => $parentResourceId, + 'parent_resource_external_id' => $parentResourceExternalId, + 'parent_resource_type_slug' => $parentResourceTypeSlug, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'POST', + path: 'authorization/resources', + body: $body, + options: $options, + ); + return AuthorizationResource::fromArray($response); + } + + /** + * Get a resource + * + * Retrieve the details of an authorization resource by its ID. + * @param string $resourceId The ID of the authorization resource. + * @return \WorkOS\Resource\AuthorizationResource + */ + public function getResource( + string $resourceId, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\AuthorizationResource { + $response = $this->client->request( + method: 'GET', + path: "authorization/resources/{$resourceId}", + options: $options, + ); + return AuthorizationResource::fromArray($response); + } + + /** + * Update a resource + * + * Update an existing authorization resource. + * @param string $resourceId The ID of the authorization resource. + * @param string|null $name A display name for the resource. + * @param string|null $description An optional description of the resource. + * @param string|null $parentResourceId The ID of the parent resource. + * @param string|null $parentResourceExternalId The external ID of the parent resource. + * @param string|null $parentResourceTypeSlug The resource type slug of the parent resource. + * @return \WorkOS\Resource\AuthorizationResource + */ + public function updateResource( + string $resourceId, + ?string $name = null, + ?string $description = null, + ?string $parentResourceId = null, + ?string $parentResourceExternalId = null, + ?string $parentResourceTypeSlug = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\AuthorizationResource { + $body = array_filter([ + 'name' => $name, + 'description' => $description, + 'parent_resource_id' => $parentResourceId, + 'parent_resource_external_id' => $parentResourceExternalId, + 'parent_resource_type_slug' => $parentResourceTypeSlug, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'PATCH', + path: "authorization/resources/{$resourceId}", + body: $body, + options: $options, + ); + return AuthorizationResource::fromArray($response); + } + + /** + * Delete an authorization resource + * + * Delete an authorization resource and all its descendants. + * @param string $resourceId The ID of the authorization resource. + * @param bool|null $cascadeDelete If true, deletes all descendant resources and role assignments. If not set and the resource has children or assignments, the request will fail. Defaults to false. + * @return void + */ + public function deleteResource( + string $resourceId, + ?bool $cascadeDelete = null, + ?\WorkOS\RequestOptions $options = null, + ): void { + $query = array_filter([ + 'cascade_delete' => $cascadeDelete, + ], fn ($v) => $v !== null); + $this->client->request( + method: 'DELETE', + path: "authorization/resources/{$resourceId}", + query: $query, + options: $options, + ); + } + + /** + * List organization memberships for resource + * + * Returns all organization memberships that have a specific permission on a resource instance. This is useful for answering "Who can access this resource?". + * @param string $resourceId The ID of the authorization resource. + * @param string|null $before An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `before="obj_123"` to fetch a new batch of objects before `"obj_123"`. + * @param string|null $after An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `after="obj_123"` to fetch a new batch of objects after `"obj_123"`. + * @param int|null $limit Upper limit on the number of objects to return, between `1` and `100`. Defaults to 10. + * @param \WorkOS\Resource\EventsOrder|null $order Order the results by the creation time. Supported values are `"asc"` (ascending), `"desc"` (descending), and `"normal"` (descending with reversed cursor semantics where `before` fetches older records and `after` fetches newer records). Defaults to descending. Defaults to "desc". + * @param string $permissionSlug The permission slug to filter by. Only users with this permission on the resource are returned. + * @param \WorkOS\Resource\AuthorizationAssignment|null $assignment Filter by assignment type. Use `direct` for direct assignments only, or `indirect` to include inherited assignments. + * @return \WorkOS\PaginatedResponse<\WorkOS\Resource\UserOrganizationMembershipBaseListData> + */ + public function listMembershipsForResource( + string $resourceId, + string $permissionSlug, + ?string $before = null, + ?string $after = null, + ?int $limit = null, + ?\WorkOS\Resource\EventsOrder $order = null, + ?\WorkOS\Resource\AuthorizationAssignment $assignment = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\PaginatedResponse { + $query = array_filter([ + 'before' => $before, + 'after' => $after, + 'limit' => $limit, + 'order' => $order?->value, + 'permission_slug' => $permissionSlug, + 'assignment' => $assignment?->value, + ], fn ($v) => $v !== null); + return $this->client->requestPage( + method: 'GET', + path: "authorization/resources/{$resourceId}/organization_memberships", + query: $query, + modelClass: UserOrganizationMembershipBaseListData::class, + options: $options, + ); + } + + /** + * List environment roles + * + * List all environment roles in priority order. + * @return \WorkOS\Resource\RoleList + */ + public function listEnvironmentRoles( + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\RoleList { + $response = $this->client->request( + method: 'GET', + path: 'authorization/roles', + options: $options, + ); + return RoleList::fromArray($response); + } + + /** + * Create an environment role + * + * Create a new environment role. + * @param string $slug A unique slug for the role. + * @param string $name A descriptive name for the role. + * @param string|null $description An optional description of the role. + * @param string|null $resourceTypeSlug The slug of the resource type the role is scoped to. + * @return \WorkOS\Resource\Role + */ + public function createEnvironmentRole( + string $slug, + string $name, + ?string $description = null, + ?string $resourceTypeSlug = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\Role { + $body = array_filter([ + 'slug' => $slug, + 'name' => $name, + 'description' => $description, + 'resource_type_slug' => $resourceTypeSlug, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'POST', + path: 'authorization/roles', + body: $body, + options: $options, + ); + return Role::fromArray($response); + } + + /** + * Get an environment role + * + * Get an environment role by its slug. + * @param string $slug The slug of the environment role. + * @return \WorkOS\Resource\Role + */ + public function getEnvironmentRole( + string $slug, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\Role { + $response = $this->client->request( + method: 'GET', + path: "authorization/roles/{$slug}", + options: $options, + ); + return Role::fromArray($response); + } + + /** + * Update an environment role + * + * Update an existing environment role. + * @param string $slug The slug of the environment role. + * @param string|null $name A descriptive name for the role. + * @param string|null $description An optional description of the role. + * @return \WorkOS\Resource\Role + */ + public function updateEnvironmentRole( + string $slug, + ?string $name = null, + ?string $description = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\Role { + $body = array_filter([ + 'name' => $name, + 'description' => $description, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'PATCH', + path: "authorization/roles/{$slug}", + body: $body, + options: $options, + ); + return Role::fromArray($response); + } + + /** + * Add a permission to an environment role + * + * Add a single permission to an environment role. If the permission is already assigned to the role, this operation has no effect. + * @param string $slug The slug of the environment role. + * @param string $bodySlug The slug of the permission to add to the role. + * @return \WorkOS\Resource\Role + */ + public function addEnvironmentRolePermission( + string $slug, + string $bodySlug, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\Role { + $body = [ + 'slug' => $bodySlug, + ]; + $response = $this->client->request( + method: 'POST', + path: "authorization/roles/{$slug}/permissions", + body: $body, + options: $options, + ); + return Role::fromArray($response); + } + + /** + * Set permissions for an environment role + * + * Replace all permissions on an environment role with the provided list. + * @param string $slug The slug of the environment role. + * @param array $permissions The permission slugs to assign to the role. + * @return \WorkOS\Resource\Role + */ + public function setEnvironmentRolePermissions( + string $slug, + array $permissions, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\Role { + $body = [ + 'permissions' => $permissions, + ]; + $response = $this->client->request( + method: 'PUT', + path: "authorization/roles/{$slug}/permissions", + body: $body, + options: $options, + ); + return Role::fromArray($response); + } + + /** + * List permissions + * + * Get a list of all permissions in your WorkOS environment. + * @param string|null $before An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `before="obj_123"` to fetch a new batch of objects before `"obj_123"`. + * @param string|null $after An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `after="obj_123"` to fetch a new batch of objects after `"obj_123"`. + * @param int|null $limit Upper limit on the number of objects to return, between `1` and `100`. Defaults to 10. + * @param \WorkOS\Resource\EventsOrder|null $order Order the results by the creation time. Supported values are `"asc"` (ascending), `"desc"` (descending), and `"normal"` (descending with reversed cursor semantics where `before` fetches older records and `after` fetches newer records). Defaults to descending. Defaults to "desc". + * @return \WorkOS\PaginatedResponse<\WorkOS\Resource\AuthorizationPermission> + */ + public function listPermissions( + ?string $before = null, + ?string $after = null, + ?int $limit = null, + ?\WorkOS\Resource\EventsOrder $order = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\PaginatedResponse { + $query = array_filter([ + 'before' => $before, + 'after' => $after, + 'limit' => $limit, + 'order' => $order?->value, + ], fn ($v) => $v !== null); + return $this->client->requestPage( + method: 'GET', + path: 'authorization/permissions', + query: $query, + modelClass: AuthorizationPermission::class, + options: $options, + ); + } + + /** + * Create a permission + * + * Create a new permission in your WorkOS environment. The permission can then be assigned to environment roles and organization roles. + * @param string $slug A unique key to reference the permission. Must be lowercase and contain only letters, numbers, hyphens, underscores, colons, periods, and asterisks. + * @param string $name A descriptive name for the Permission. + * @param string|null $description An optional description of the Permission. + * @param string|null $resourceTypeSlug The slug of the resource type this permission is scoped to. + * @return \WorkOS\Resource\Permission + */ + public function createPermission( + string $slug, + string $name, + ?string $description = null, + ?string $resourceTypeSlug = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\Permission { + $body = array_filter([ + 'slug' => $slug, + 'name' => $name, + 'description' => $description, + 'resource_type_slug' => $resourceTypeSlug, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'POST', + path: 'authorization/permissions', + body: $body, + options: $options, + ); + return Permission::fromArray($response); + } + + /** + * Get a permission + * + * Retrieve a permission by its unique slug. + * @param string $slug A unique key to reference the permission. Must be lowercase and contain only letters, numbers, hyphens, underscores, colons, periods, and asterisks. + * @return \WorkOS\Resource\AuthorizationPermission + */ + public function getPermission( + string $slug, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\AuthorizationPermission { + $response = $this->client->request( + method: 'GET', + path: "authorization/permissions/{$slug}", + options: $options, + ); + return AuthorizationPermission::fromArray($response); + } + + /** + * Update a permission + * + * Update an existing permission. Only the fields provided in the request body will be updated. + * @param string $slug A unique key to reference the permission. Must be lowercase and contain only letters, numbers, hyphens, underscores, colons, periods, and asterisks. + * @param string|null $name A descriptive name for the Permission. + * @param string|null $description An optional description of the Permission. + * @return \WorkOS\Resource\AuthorizationPermission + */ + public function updatePermission( + string $slug, + ?string $name = null, + ?string $description = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\AuthorizationPermission { + $body = array_filter([ + 'name' => $name, + 'description' => $description, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'PATCH', + path: "authorization/permissions/{$slug}", + body: $body, + options: $options, + ); + return AuthorizationPermission::fromArray($response); + } + + /** + * Delete a permission + * + * Delete an existing permission. System permissions cannot be deleted. + * @param string $slug A unique key to reference the permission. Must be lowercase and contain only letters, numbers, hyphens, underscores, colons, periods, and asterisks. + * @return void + */ + public function deletePermission( + string $slug, + ?\WorkOS\RequestOptions $options = null, + ): void { + $this->client->request( + method: 'DELETE', + path: "authorization/permissions/{$slug}", + options: $options, + ); + } +} diff --git a/lib/Service/Connect.php b/lib/Service/Connect.php new file mode 100644 index 00000000..a977cea0 --- /dev/null +++ b/lib/Service/Connect.php @@ -0,0 +1,294 @@ +|null $userConsentOptions Array of [User Consent Options](https://workos.com/docs/reference/workos-connect/standalone/user-consent-options) to store with the session. + * @return \WorkOS\Resource\ExternalAuthCompleteResponse + */ + public function completeOAuth2( + string $externalAuthId, + \WorkOS\Resource\UserObject $user, + ?array $userConsentOptions = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\ExternalAuthCompleteResponse { + $body = array_filter([ + 'external_auth_id' => $externalAuthId, + 'user' => $user, + 'user_consent_options' => $userConsentOptions, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'POST', + path: 'authkit/oauth2/complete', + body: $body, + options: $options, + ); + return ExternalAuthCompleteResponse::fromArray($response); + } + + /** + * List Connect Applications + * + * List all Connect Applications in the current environment with optional filtering. + * @param string|null $before An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `before="obj_123"` to fetch a new batch of objects before `"obj_123"`. + * @param string|null $after An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `after="obj_123"` to fetch a new batch of objects after `"obj_123"`. + * @param int|null $limit Upper limit on the number of objects to return, between `1` and `100`. Defaults to 10. + * @param \WorkOS\Resource\EventsOrder|null $order Order the results by the creation time. Supported values are `"asc"` (ascending), `"desc"` (descending), and `"normal"` (descending with reversed cursor semantics where `before` fetches older records and `after` fetches newer records). Defaults to descending. Defaults to "desc". + * @param string|null $organizationId Filter Connect Applications by organization ID. + * @return \WorkOS\PaginatedResponse<\WorkOS\Resource\ConnectApplication> + */ + public function listApplications( + ?string $before = null, + ?string $after = null, + ?int $limit = null, + ?\WorkOS\Resource\EventsOrder $order = null, + ?string $organizationId = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\PaginatedResponse { + $query = array_filter([ + 'before' => $before, + 'after' => $after, + 'limit' => $limit, + 'order' => $order?->value, + 'organization_id' => $organizationId, + ], fn ($v) => $v !== null); + return $this->client->requestPage( + method: 'GET', + path: 'connect/applications', + query: $query, + modelClass: ConnectApplication::class, + options: $options, + ); + } + + /** + * @param string $name + * @param bool $isFirstParty + * @param string|null $description + * @param array|null $scopes + * @param array<\WorkOS\Resource\RedirectUriInput>|null $redirectUris + * @param bool|null $usesPkce + * @param string|null $organizationId + * @return \WorkOS\Resource\ConnectApplication + */ + public function createOAuthApplication( + string $name, + bool $isFirstParty, + ?string $description = null, + ?array $scopes = null, + ?array $redirectUris = null, + ?bool $usesPkce = null, + ?string $organizationId = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\ConnectApplication { + $body = array_filter([ + 'application_type' => 'oauth', + 'name' => $name, + 'is_first_party' => $isFirstParty, + 'description' => $description, + 'scopes' => $scopes, + 'redirect_uris' => $redirectUris, + 'uses_pkce' => $usesPkce, + 'organization_id' => $organizationId, + ], fn ($v) => $v !== null); + + $response = $this->client->request( + method: 'POST', + path: 'connect/applications', + body: $body, + options: $options, + ); + return ConnectApplication::fromArray($response); + } + + /** + * @param string $name + * @param string $organizationId + * @param string|null $description + * @param array|null $scopes + * @return \WorkOS\Resource\ConnectApplication + */ + public function createM2MApplication( + string $name, + string $organizationId, + ?string $description = null, + ?array $scopes = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\ConnectApplication { + $body = array_filter([ + 'application_type' => 'm2m', + 'name' => $name, + 'organization_id' => $organizationId, + 'description' => $description, + 'scopes' => $scopes, + ], fn ($v) => $v !== null); + + $response = $this->client->request( + method: 'POST', + path: 'connect/applications', + body: $body, + options: $options, + ); + return ConnectApplication::fromArray($response); + } + + /** + * Get a Connect Application + * + * Retrieve details for a specific Connect Application by ID or client ID. + * @param string $id The application ID or client ID of the Connect Application. + * @return \WorkOS\Resource\ConnectApplication + */ + public function getApplication( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\ConnectApplication { + $response = $this->client->request( + method: 'GET', + path: "connect/applications/{$id}", + options: $options, + ); + return ConnectApplication::fromArray($response); + } + + /** + * Update a Connect Application + * + * Update an existing Connect Application. For OAuth applications, you can update redirect URIs. For all applications, you can update the name, description, and scopes. + * @param string $id The application ID or client ID of the Connect Application. + * @param string|null $name The name of the application. + * @param string|null $description A description for the application. + * @param array|null $scopes The OAuth scopes granted to the application. + * @param array<\WorkOS\Resource\RedirectUriInput>|null $redirectUris Updated redirect URIs for the application. OAuth applications only. + * @return \WorkOS\Resource\ConnectApplication + */ + public function updateApplication( + string $id, + ?string $name = null, + ?string $description = null, + ?array $scopes = null, + ?array $redirectUris = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\ConnectApplication { + $body = array_filter([ + 'name' => $name, + 'description' => $description, + 'scopes' => $scopes, + 'redirect_uris' => $redirectUris, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'PUT', + path: "connect/applications/{$id}", + body: $body, + options: $options, + ); + return ConnectApplication::fromArray($response); + } + + /** + * Delete a Connect Application + * + * Delete an existing Connect Application. + * @param string $id The application ID or client ID of the Connect Application. + * @return void + */ + public function deleteApplication( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): void { + $this->client->request( + method: 'DELETE', + path: "connect/applications/{$id}", + options: $options, + ); + } + + /** + * List Client Secrets for a Connect Application + * + * List all client secrets associated with a Connect Application. + * @param string $id The application ID or client ID of the Connect Application. + * @return array + */ + public function listApplicationClientSecrets( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): array { + $response = $this->client->request( + method: 'GET', + path: "connect/applications/{$id}/client_secrets", + options: $options, + ); + return array_map(fn ($item) => ApplicationCredentialsListItem::fromArray($item), $response); + } + + /** + * Create a new client secret for a Connect Application + * + * Create new secrets for a Connect Application. + * @param string $id The application ID or client ID of the Connect Application. + * @return \WorkOS\Resource\NewConnectApplicationSecret + */ + public function createApplicationClientSecrets( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\NewConnectApplicationSecret { + $body = [ + ]; + $response = $this->client->request( + method: 'POST', + path: "connect/applications/{$id}/client_secrets", + body: $body, + options: $options, + ); + return NewConnectApplicationSecret::fromArray($response); + } + + /** + * Delete a Client Secret + * + * Delete (revoke) an existing client secret. + * @param string $id The unique ID of the client secret. + * @return void + */ + public function deleteClientSecret( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): void { + $this->client->request( + method: 'DELETE', + path: "connect/client_secrets/{$id}", + options: $options, + ); + } +} diff --git a/lib/Service/DirectorySync.php b/lib/Service/DirectorySync.php new file mode 100644 index 00000000..feb1206f --- /dev/null +++ b/lib/Service/DirectorySync.php @@ -0,0 +1,211 @@ + + */ + public function listDirectories( + ?string $before = null, + ?string $after = null, + ?int $limit = null, + ?\WorkOS\Resource\EventsOrder $order = null, + ?string $organizationId = null, + ?string $search = null, + ?string $domain = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\PaginatedResponse { + $query = array_filter([ + 'before' => $before, + 'after' => $after, + 'limit' => $limit, + 'order' => $order?->value, + 'organization_id' => $organizationId, + 'search' => $search, + 'domain' => $domain, + ], fn ($v) => $v !== null); + return $this->client->requestPage( + method: 'GET', + path: 'directories', + query: $query, + modelClass: Directory::class, + options: $options, + ); + } + + /** + * Get a Directory + * + * Get the details of an existing directory. + * @param string $id Unique identifier for the Directory. + * @return \WorkOS\Resource\Directory + */ + public function getDirectory( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\Directory { + $response = $this->client->request( + method: 'GET', + path: "directories/{$id}", + options: $options, + ); + return Directory::fromArray($response); + } + + /** + * Delete a Directory + * + * Permanently deletes an existing directory. It cannot be undone. + * @param string $id Unique identifier for the Directory. + * @return void + */ + public function deleteDirectory( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): void { + $this->client->request( + method: 'DELETE', + path: "directories/{$id}", + options: $options, + ); + } + + /** + * List Directory Groups + * + * Get a list of all of existing directory groups matching the criteria specified. + * @param string|null $before An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `before="obj_123"` to fetch a new batch of objects before `"obj_123"`. + * @param string|null $after An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `after="obj_123"` to fetch a new batch of objects after `"obj_123"`. + * @param int|null $limit Upper limit on the number of objects to return, between `1` and `100`. Defaults to 10. + * @param \WorkOS\Resource\EventsOrder|null $order Order the results by the creation time. Supported values are `"asc"` (ascending), `"desc"` (descending), and `"normal"` (descending with reversed cursor semantics where `before` fetches older records and `after` fetches newer records). Defaults to descending. Defaults to "desc". + * @param string|null $directory Unique identifier of the WorkOS Directory. This value can be obtained from the WorkOS dashboard or from the WorkOS API. + * @param string|null $user Unique identifier of the WorkOS Directory User. This value can be obtained from the WorkOS API. + * @return \WorkOS\PaginatedResponse<\WorkOS\Resource\DirectoryGroup> + */ + public function listGroups( + ?string $before = null, + ?string $after = null, + ?int $limit = null, + ?\WorkOS\Resource\EventsOrder $order = null, + ?string $directory = null, + ?string $user = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\PaginatedResponse { + $query = array_filter([ + 'before' => $before, + 'after' => $after, + 'limit' => $limit, + 'order' => $order?->value, + 'directory' => $directory, + 'user' => $user, + ], fn ($v) => $v !== null); + return $this->client->requestPage( + method: 'GET', + path: 'directory_groups', + query: $query, + modelClass: DirectoryGroup::class, + options: $options, + ); + } + + /** + * Get a Directory Group + * + * Get the details of an existing Directory Group. + * @param string $id Unique identifier for the Directory Group. + * @return \WorkOS\Resource\DirectoryGroup + */ + public function getGroup( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\DirectoryGroup { + $response = $this->client->request( + method: 'GET', + path: "directory_groups/{$id}", + options: $options, + ); + return DirectoryGroup::fromArray($response); + } + + /** + * List Directory Users + * + * Get a list of all of existing Directory Users matching the criteria specified. + * @param string|null $before An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `before="obj_123"` to fetch a new batch of objects before `"obj_123"`. + * @param string|null $after An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `after="obj_123"` to fetch a new batch of objects after `"obj_123"`. + * @param int|null $limit Upper limit on the number of objects to return, between `1` and `100`. Defaults to 10. + * @param \WorkOS\Resource\EventsOrder|null $order Order the results by the creation time. Supported values are `"asc"` (ascending), `"desc"` (descending), and `"normal"` (descending with reversed cursor semantics where `before` fetches older records and `after` fetches newer records). Defaults to descending. Defaults to "desc". + * @param string|null $directory Unique identifier of the WorkOS Directory. This value can be obtained from the WorkOS dashboard or from the WorkOS API. + * @param string|null $group Unique identifier of the WorkOS Directory Group. This value can be obtained from the WorkOS API. + * @return \WorkOS\PaginatedResponse<\WorkOS\Resource\DirectoryUserWithGroups> + */ + public function listUsers( + ?string $before = null, + ?string $after = null, + ?int $limit = null, + ?\WorkOS\Resource\EventsOrder $order = null, + ?string $directory = null, + ?string $group = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\PaginatedResponse { + $query = array_filter([ + 'before' => $before, + 'after' => $after, + 'limit' => $limit, + 'order' => $order?->value, + 'directory' => $directory, + 'group' => $group, + ], fn ($v) => $v !== null); + return $this->client->requestPage( + method: 'GET', + path: 'directory_users', + query: $query, + modelClass: DirectoryUserWithGroups::class, + options: $options, + ); + } + + /** + * Get a Directory User + * + * Get the details of an existing Directory User. + * @param string $id Unique identifier for the Directory User. + * @return \WorkOS\Resource\DirectoryUserWithGroups + */ + public function getUser( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\DirectoryUserWithGroups { + $response = $this->client->request( + method: 'GET', + path: "directory_users/{$id}", + options: $options, + ); + return DirectoryUserWithGroups::fromArray($response); + } +} diff --git a/lib/Service/Events.php b/lib/Service/Events.php new file mode 100644 index 00000000..4558b7d9 --- /dev/null +++ b/lib/Service/Events.php @@ -0,0 +1,61 @@ +|null $events Filter events by one or more event types (e.g. `dsync.user.created`). + * @param string|null $rangeStart ISO-8601 date string to filter events created after this date. + * @param string|null $rangeEnd ISO-8601 date string to filter events created before this date. + * @param string|null $organizationId Filter events by the [Organization](https://workos.com/docs/reference/organization) that the event is associated with. + * @return \WorkOS\PaginatedResponse<\WorkOS\Resource\EventSchema> + */ + public function listEvents( + ?string $before = null, + ?string $after = null, + ?int $limit = null, + ?\WorkOS\Resource\EventsOrder $order = null, + ?array $events = null, + ?string $rangeStart = null, + ?string $rangeEnd = null, + ?string $organizationId = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\PaginatedResponse { + $query = array_filter([ + 'before' => $before, + 'after' => $after, + 'limit' => $limit, + 'order' => $order?->value, + 'events' => $events, + 'range_start' => $rangeStart, + 'range_end' => $rangeEnd, + 'organization_id' => $organizationId, + ], fn ($v) => $v !== null); + return $this->client->requestPage( + method: 'GET', + path: 'events', + query: $query, + modelClass: EventSchema::class, + options: $options, + ); + } +} diff --git a/lib/Service/FeatureFlags.php b/lib/Service/FeatureFlags.php new file mode 100644 index 00000000..353acd0d --- /dev/null +++ b/lib/Service/FeatureFlags.php @@ -0,0 +1,216 @@ + + */ + public function listFeatureFlags( + ?string $before = null, + ?string $after = null, + ?int $limit = null, + ?\WorkOS\Resource\EventsOrder $order = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\PaginatedResponse { + $query = array_filter([ + 'before' => $before, + 'after' => $after, + 'limit' => $limit, + 'order' => $order?->value, + ], fn ($v) => $v !== null); + return $this->client->requestPage( + method: 'GET', + path: 'feature-flags', + query: $query, + modelClass: Flag::class, + options: $options, + ); + } + + /** + * Get a feature flag + * + * Get the details of an existing feature flag by its slug. + * @param string $slug A unique key to reference the Feature Flag. + * @return \WorkOS\Resource\Flag + */ + public function getFeatureFlag( + string $slug, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\Flag { + $response = $this->client->request( + method: 'GET', + path: "feature-flags/{$slug}", + options: $options, + ); + return Flag::fromArray($response); + } + + /** + * Disable a feature flag + * + * Disables a feature flag in the current environment. + * @param string $slug A unique key to reference the Feature Flag. + * @return \WorkOS\Resource\FeatureFlag + */ + public function disableFeatureFlag( + string $slug, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\FeatureFlag { + $response = $this->client->request( + method: 'PUT', + path: "feature-flags/{$slug}/disable", + options: $options, + ); + return FeatureFlag::fromArray($response); + } + + /** + * Enable a feature flag + * + * Enables a feature flag in the current environment. + * @param string $slug A unique key to reference the Feature Flag. + * @return \WorkOS\Resource\FeatureFlag + */ + public function enableFeatureFlag( + string $slug, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\FeatureFlag { + $response = $this->client->request( + method: 'PUT', + path: "feature-flags/{$slug}/enable", + options: $options, + ); + return FeatureFlag::fromArray($response); + } + + /** + * Add a feature flag target + * + * Enables a feature flag for a specific target in the current environment. Currently, supported targets include users and organizations. + * @param string $resourceId The resource ID in format "user_" or "org_". + * @param string $slug The unique slug identifier of the feature flag. + * @return mixed + */ + public function addFlagTarget( + string $resourceId, + string $slug, + ?\WorkOS\RequestOptions $options = null, + ): mixed { + $response = $this->client->request( + method: 'POST', + path: "feature-flags/{$slug}/targets/{$resourceId}", + options: $options, + ); + return $response; + } + + /** + * Remove a feature flag target + * + * Removes a target from the feature flag's target list in the current environment. Currently, supported targets include users and organizations. + * @param string $resourceId The resource ID in format "user_" or "org_". + * @param string $slug The unique slug identifier of the feature flag. + * @return void + */ + public function removeFlagTarget( + string $resourceId, + string $slug, + ?\WorkOS\RequestOptions $options = null, + ): void { + $this->client->request( + method: 'DELETE', + path: "feature-flags/{$slug}/targets/{$resourceId}", + options: $options, + ); + } + + /** + * List enabled feature flags for an organization + * + * Get a list of all enabled feature flags for an organization. + * @param string $organizationId Unique identifier of the Organization. + * @param string|null $before An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. + * @param string|null $after An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. + * @param int|null $limit Upper limit on the number of objects to return, between `1` and `100`. Defaults to 10. + * @param \WorkOS\Resource\EventsOrder|null $order Order the results by the creation time. Defaults to "desc". + * @return \WorkOS\PaginatedResponse<\WorkOS\Resource\Flag> + */ + public function listOrganizationFeatureFlags( + string $organizationId, + ?string $before = null, + ?string $after = null, + ?int $limit = null, + ?\WorkOS\Resource\EventsOrder $order = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\PaginatedResponse { + $query = array_filter([ + 'before' => $before, + 'after' => $after, + 'limit' => $limit, + 'order' => $order?->value, + ], fn ($v) => $v !== null); + return $this->client->requestPage( + method: 'GET', + path: "organizations/{$organizationId}/feature-flags", + query: $query, + modelClass: Flag::class, + options: $options, + ); + } + + /** + * List enabled feature flags for a user + * + * Get a list of all enabled feature flags for the provided user. This includes feature flags enabled specifically for the user as well as any organizations that the user is a member of. + * @param string $userId The ID of the user. + * @param string|null $before An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. + * @param string|null $after An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. + * @param int|null $limit Upper limit on the number of objects to return, between `1` and `100`. Defaults to 10. + * @param \WorkOS\Resource\EventsOrder|null $order Order the results by the creation time. Defaults to "desc". + * @return \WorkOS\PaginatedResponse<\WorkOS\Resource\Flag> + */ + public function listUserFeatureFlags( + string $userId, + ?string $before = null, + ?string $after = null, + ?int $limit = null, + ?\WorkOS\Resource\EventsOrder $order = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\PaginatedResponse { + $query = array_filter([ + 'before' => $before, + 'after' => $after, + 'limit' => $limit, + 'order' => $order?->value, + ], fn ($v) => $v !== null); + return $this->client->requestPage( + method: 'GET', + path: "user_management/users/{$userId}/feature-flags", + query: $query, + modelClass: Flag::class, + options: $options, + ); + } +} diff --git a/lib/Service/MultiFactorAuth.php b/lib/Service/MultiFactorAuth.php new file mode 100644 index 00000000..cbd1a2bf --- /dev/null +++ b/lib/Service/MultiFactorAuth.php @@ -0,0 +1,211 @@ + $code, + ]; + $response = $this->client->request( + method: 'POST', + path: "auth/challenges/{$id}/verify", + body: $body, + options: $options, + ); + return AuthenticationChallengeVerifyResponse::fromArray($response); + } + + /** + * Enroll Factor + * + * Enrolls an Authentication Factor to be used as an additional factor of authentication. The returned ID should be used to create an authentication Challenge. + * @param \WorkOS\Resource\AuthenticationFactorsCreateRequestType $type The type of factor to enroll. + * @param string|null $phoneNumber Required when type is 'sms'. + * @param string|null $totpIssuer Required when type is 'totp'. + * @param string|null $totpUser Required when type is 'totp'. + * @param string|null $userId The ID of the user to associate the factor with. + * @return \WorkOS\Resource\AuthenticationFactorEnrolled + */ + public function enrollFactor( + \WorkOS\Resource\AuthenticationFactorsCreateRequestType $type, + ?string $phoneNumber = null, + ?string $totpIssuer = null, + ?string $totpUser = null, + ?string $userId = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\AuthenticationFactorEnrolled { + $body = array_filter([ + 'type' => $type->value, + 'phone_number' => $phoneNumber, + 'totp_issuer' => $totpIssuer, + 'totp_user' => $totpUser, + 'user_id' => $userId, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'POST', + path: 'auth/factors/enroll', + body: $body, + options: $options, + ); + return AuthenticationFactorEnrolled::fromArray($response); + } + + /** + * Get Factor + * + * Gets an Authentication Factor. + * @param string $id The unique ID of the Factor. + * @return \WorkOS\Resource\AuthenticationFactor + */ + public function getFactor( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\AuthenticationFactor { + $response = $this->client->request( + method: 'GET', + path: "auth/factors/{$id}", + options: $options, + ); + return AuthenticationFactor::fromArray($response); + } + + /** + * Delete Factor + * + * Permanently deletes an Authentication Factor. It cannot be undone. + * @param string $id The unique ID of the Factor. + * @return void + */ + public function deleteFactor( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): void { + $this->client->request( + method: 'DELETE', + path: "auth/factors/{$id}", + options: $options, + ); + } + + /** + * Challenge Factor + * + * Creates a Challenge for an Authentication Factor. + * @param string $id The unique ID of the Authentication Factor to be challenged. + * @param string|null $smsTemplate A custom template for the SMS message. Use the {{code}} placeholder to include the verification code. + * @return \WorkOS\Resource\AuthenticationChallenge + */ + public function challengeFactor( + string $id, + ?string $smsTemplate = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\AuthenticationChallenge { + $body = array_filter([ + 'sms_template' => $smsTemplate, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'POST', + path: "auth/factors/{$id}/challenge", + body: $body, + options: $options, + ); + return AuthenticationChallenge::fromArray($response); + } + + /** + * List authentication factors + * + * Lists the [authentication factors](https://workos.com/docs/reference/authkit/mfa/authentication-factor) for a user. + * @param string $userlandUserId The ID of the [user](https://workos.com/docs/reference/authkit/user). + * @param string|null $before An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. + * @param string|null $after An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. + * @param int|null $limit Upper limit on the number of objects to return, between `1` and `100`. Defaults to 10. + * @param \WorkOS\Resource\EventsOrder|null $order Order the results by the creation time. Defaults to "desc". + * @return \WorkOS\PaginatedResponse<\WorkOS\Resource\AuthenticationFactor> + */ + public function listUserAuthFactors( + string $userlandUserId, + ?string $before = null, + ?string $after = null, + ?int $limit = null, + ?\WorkOS\Resource\EventsOrder $order = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\PaginatedResponse { + $query = array_filter([ + 'before' => $before, + 'after' => $after, + 'limit' => $limit, + 'order' => $order?->value, + ], fn ($v) => $v !== null); + return $this->client->requestPage( + method: 'GET', + path: "user_management/users/{$userlandUserId}/auth_factors", + query: $query, + modelClass: AuthenticationFactor::class, + options: $options, + ); + } + + /** + * Enroll an authentication factor + * + * Enrolls a user in a new [authentication factor](https://workos.com/docs/reference/authkit/mfa/authentication-factor). + * @param string $userlandUserId The ID of the [user](https://workos.com/docs/reference/authkit/user). + * @param string $type The type of the factor to enroll. + * @param string|null $totpIssuer Your application or company name displayed in the user's authenticator app. + * @param string|null $totpUser The user's account name displayed in their authenticator app. + * @param string|null $totpSecret The Base32-encoded shared secret for TOTP factors. This can be provided when creating the auth factor, otherwise it will be generated. The algorithm used to derive TOTP codes is SHA-1, the code length is 6 digits, and the timestep is 30 seconds – the secret must be compatible with these parameters. + * @return \WorkOS\Resource\UserAuthenticationFactorEnrollResponse + */ + public function createUserAuthFactors( + string $userlandUserId, + string $type, + ?string $totpIssuer = null, + ?string $totpUser = null, + ?string $totpSecret = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\UserAuthenticationFactorEnrollResponse { + $body = array_filter([ + 'type' => $type, + 'totp_issuer' => $totpIssuer, + 'totp_user' => $totpUser, + 'totp_secret' => $totpSecret, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'POST', + path: "user_management/users/{$userlandUserId}/auth_factors", + body: $body, + options: $options, + ); + return UserAuthenticationFactorEnrollResponse::fromArray($response); + } +} diff --git a/lib/Service/OrganizationDomains.php b/lib/Service/OrganizationDomains.php new file mode 100644 index 00000000..5fdb1e0b --- /dev/null +++ b/lib/Service/OrganizationDomains.php @@ -0,0 +1,100 @@ + $domain, + 'organization_id' => $organizationId, + ]; + $response = $this->client->request( + method: 'POST', + path: 'organization_domains', + body: $body, + options: $options, + ); + return OrganizationDomain::fromArray($response); + } + + /** + * Get an Organization Domain + * + * Get the details of an existing organization domain. + * @param string $id Unique identifier of the organization domain. + * @return \WorkOS\Resource\OrganizationDomainStandAlone + */ + public function getOrganizationDomain( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\OrganizationDomainStandAlone { + $response = $this->client->request( + method: 'GET', + path: "organization_domains/{$id}", + options: $options, + ); + return OrganizationDomainStandAlone::fromArray($response); + } + + /** + * Delete an Organization Domain + * + * Permanently deletes an organization domain. It cannot be undone. + * @param string $id Unique identifier of the organization domain. + * @return void + */ + public function deleteOrganizationDomain( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): void { + $this->client->request( + method: 'DELETE', + path: "organization_domains/{$id}", + options: $options, + ); + } + + /** + * Verify an Organization Domain + * + * Initiates verification process for an Organization Domain. + * @param string $id Unique identifier of the organization domain. + * @return \WorkOS\Resource\OrganizationDomainStandAlone + */ + public function verifyOrganizationDomain( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\OrganizationDomainStandAlone { + $response = $this->client->request( + method: 'POST', + path: "organization_domains/{$id}/verify", + options: $options, + ); + return OrganizationDomainStandAlone::fromArray($response); + } +} diff --git a/lib/Service/Organizations.php b/lib/Service/Organizations.php new file mode 100644 index 00000000..0efcca92 --- /dev/null +++ b/lib/Service/Organizations.php @@ -0,0 +1,212 @@ +|null $domains The domains of an Organization. Any Organization with a matching domain will be returned. + * @param string|null $search Searchable text for an Organization. Matches against the organization name. + * @return \WorkOS\PaginatedResponse<\WorkOS\Resource\Organization> + */ + public function listOrganizations( + ?string $before = null, + ?string $after = null, + ?int $limit = null, + ?\WorkOS\Resource\EventsOrder $order = null, + ?array $domains = null, + ?string $search = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\PaginatedResponse { + $query = array_filter([ + 'before' => $before, + 'after' => $after, + 'limit' => $limit, + 'order' => $order?->value, + 'domains' => $domains, + 'search' => $search, + ], fn ($v) => $v !== null); + return $this->client->requestPage( + method: 'GET', + path: 'organizations', + query: $query, + modelClass: Organization::class, + options: $options, + ); + } + + /** + * Create an Organization + * + * Creates a new organization in the current environment. + * @param string $name The name of the organization. + * @param bool|null $allowProfilesOutsideOrganization Whether the organization allows profiles from outside the organization to sign in. + * @param array|null $domains The domains associated with the organization. Deprecated in favor of `domain_data`. + * @param array<\WorkOS\Resource\OrganizationDomainData>|null $domainData The domains associated with the organization, including verification state. + * @param array|null $metadata Object containing [metadata](https://workos.com/docs/authkit/metadata) key/value pairs associated with the Organization. + * @param string|null $externalId An external identifier for the Organization. + * @return \WorkOS\Resource\Organization + */ + public function createOrganization( + string $name, + ?bool $allowProfilesOutsideOrganization = null, + ?array $domains = null, + ?array $domainData = null, + ?array $metadata = null, + ?string $externalId = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\Organization { + $body = array_filter([ + 'name' => $name, + 'allow_profiles_outside_organization' => $allowProfilesOutsideOrganization, + 'domains' => $domains, + 'domain_data' => $domainData, + 'metadata' => $metadata, + 'external_id' => $externalId, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'POST', + path: 'organizations', + body: $body, + options: $options, + ); + return Organization::fromArray($response); + } + + /** + * Get an Organization by External ID + * + * Get the details of an existing organization by an [external identifier](https://workos.com/docs/authkit/metadata/external-identifiers). + * @param string $externalId The external ID of the Organization. + * @return \WorkOS\Resource\Organization + */ + public function getOrganizationByExternalId( + string $externalId, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\Organization { + $response = $this->client->request( + method: 'GET', + path: "organizations/external_id/{$externalId}", + options: $options, + ); + return Organization::fromArray($response); + } + + /** + * Get an Organization + * + * Get the details of an existing organization. + * @param string $id Unique identifier of the Organization. + * @return \WorkOS\Resource\Organization + */ + public function getOrganization( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\Organization { + $response = $this->client->request( + method: 'GET', + path: "organizations/{$id}", + options: $options, + ); + return Organization::fromArray($response); + } + + /** + * Update an Organization + * + * Updates an organization in the current environment. + * @param string $id Unique identifier of the Organization. + * @param string|null $name The name of the organization. + * @param bool|null $allowProfilesOutsideOrganization Whether the organization allows profiles from outside the organization to sign in. + * @param array|null $domains (deprecated) The domains associated with the organization. Deprecated in favor of `domain_data`. + * @param array<\WorkOS\Resource\OrganizationDomainData>|null $domainData The domains associated with the organization, including verification state. + * @param string|null $stripeCustomerId The Stripe customer ID associated with the organization. + * @param array|null $metadata Object containing [metadata](https://workos.com/docs/authkit/metadata) key/value pairs associated with the Organization. + * @param string|null $externalId An external identifier for the Organization. + * @return \WorkOS\Resource\Organization + */ + public function updateOrganization( + string $id, + ?string $name = null, + ?bool $allowProfilesOutsideOrganization = null, + ?array $domains = null, + ?array $domainData = null, + ?string $stripeCustomerId = null, + ?array $metadata = null, + ?string $externalId = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\Organization { + $body = array_filter([ + 'name' => $name, + 'allow_profiles_outside_organization' => $allowProfilesOutsideOrganization, + 'domains' => $domains, + 'domain_data' => $domainData, + 'stripe_customer_id' => $stripeCustomerId, + 'metadata' => $metadata, + 'external_id' => $externalId, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'PUT', + path: "organizations/{$id}", + body: $body, + options: $options, + ); + return Organization::fromArray($response); + } + + /** + * Delete an Organization + * + * Permanently deletes an organization in the current environment. It cannot be undone. + * @param string $id Unique identifier of the Organization. + * @return void + */ + public function deleteOrganization( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): void { + $this->client->request( + method: 'DELETE', + path: "organizations/{$id}", + options: $options, + ); + } + + /** + * Get Audit Log Configuration + * + * Get the unified view of audit log trail and stream configuration for an organization. + * @param string $id Unique identifier of the Organization. + * @return \WorkOS\Resource\AuditLogConfiguration + */ + public function listOrganizationAuditLogConfiguration( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\AuditLogConfiguration { + $response = $this->client->request( + method: 'GET', + path: "organizations/{$id}/audit_log_configuration", + options: $options, + ); + return AuditLogConfiguration::fromArray($response); + } +} diff --git a/lib/Service/Pipes.php b/lib/Service/Pipes.php new file mode 100644 index 00000000..2fb39450 --- /dev/null +++ b/lib/Service/Pipes.php @@ -0,0 +1,157 @@ + $userId, + 'organization_id' => $organizationId, + 'return_to' => $returnTo, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'POST', + path: "data-integrations/{$slug}/authorize", + body: $body, + options: $options, + ); + return DataIntegrationAuthorizeUrlResponse::fromArray($response); + } + + /** + * Get an access token for a connected account + * + * Fetches a valid OAuth access token for a user's connected account. WorkOS automatically handles token refresh, ensuring you always receive a valid, non-expired token. + * @param string $slug The identifier of the integration. + * @param string $userId A [User](https://workos.com/docs/reference/authkit/user) identifier. + * @param string|null $organizationId An [Organization](https://workos.com/docs/reference/organization) identifier. Optional parameter to scope the connection to a specific organization. + * @return \WorkOS\Resource\DataIntegrationAccessTokenResponse + */ + public function createDataIntegrationToken( + string $slug, + string $userId, + ?string $organizationId = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\DataIntegrationAccessTokenResponse { + $body = array_filter([ + 'user_id' => $userId, + 'organization_id' => $organizationId, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'POST', + path: "data-integrations/{$slug}/token", + body: $body, + options: $options, + ); + return DataIntegrationAccessTokenResponse::fromArray($response); + } + + /** + * Get a connected account + * + * Retrieves a user's [connected account](https://workos.com/docs/reference/pipes/connected-account) for a specific provider. + * @param string $userId A [User](https://workos.com/docs/reference/authkit/user) identifier. + * @param string $slug The slug identifier of the provider (e.g., `github`, `slack`, `notion`). + * @param string|null $organizationId An [Organization](https://workos.com/docs/reference/organization) identifier. Optional parameter if the connection is scoped to an organization. + * @return \WorkOS\Resource\ConnectedAccount + */ + public function getUserConnectedAccount( + string $userId, + string $slug, + ?string $organizationId = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\ConnectedAccount { + $query = array_filter([ + 'organization_id' => $organizationId, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'GET', + path: "user_management/users/{$userId}/connected_accounts/{$slug}", + query: $query, + options: $options, + ); + return ConnectedAccount::fromArray($response); + } + + /** + * Delete a connected account + * + * Disconnects WorkOS's account for the user, including removing any stored access and refresh tokens. The user will need to reauthorize if they want to reconnect. This does not revoke access on the provider side. + * @param string $userId A [User](https://workos.com/docs/reference/authkit/user) identifier. + * @param string $slug The slug identifier of the provider (e.g., `github`, `slack`, `notion`). + * @param string|null $organizationId An [Organization](https://workos.com/docs/reference/organization) identifier. Optional parameter if the connection is scoped to an organization. + * @return void + */ + public function deleteUserConnectedAccount( + string $userId, + string $slug, + ?string $organizationId = null, + ?\WorkOS\RequestOptions $options = null, + ): void { + $query = array_filter([ + 'organization_id' => $organizationId, + ], fn ($v) => $v !== null); + $this->client->request( + method: 'DELETE', + path: "user_management/users/{$userId}/connected_accounts/{$slug}", + query: $query, + options: $options, + ); + } + + /** + * List providers + * + * Retrieves a list of available providers and the user's connection status for each. Returns all providers configured for your environment, along with the user's [connected account](https://workos.com/docs/reference/pipes/connected-account) information where applicable. + * @param string $userId A [User](https://workos.com/docs/reference/authkit/user) identifier to list providers and connected accounts for. + * @param string|null $organizationId An [Organization](https://workos.com/docs/reference/organization) identifier. Optional parameter to filter connections for a specific organization. + * @return \WorkOS\Resource\DataIntegrationsListResponse + */ + public function listUserDataProviders( + string $userId, + ?string $organizationId = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\DataIntegrationsListResponse { + $query = array_filter([ + 'organization_id' => $organizationId, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'GET', + path: "user_management/users/{$userId}/data_providers", + query: $query, + options: $options, + ); + return DataIntegrationsListResponse::fromArray($response); + } +} diff --git a/lib/Service/Radar.php b/lib/Service/Radar.php new file mode 100644 index 00000000..ea2cc52b --- /dev/null +++ b/lib/Service/Radar.php @@ -0,0 +1,140 @@ + $ipAddress, + 'user_agent' => $userAgent, + 'email' => $email, + 'auth_method' => $authMethod->value, + 'action' => $action->value, + 'device_fingerprint' => $deviceFingerprint, + 'bot_score' => $botScore, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'POST', + path: 'radar/attempts', + body: $body, + options: $options, + ); + return RadarStandaloneResponse::fromArray($response); + } + + /** + * Update a Radar attempt + * + * You may optionally inform Radar that an authentication attempt or challenge was successful using this endpoint. Some Radar controls depend on tracking recent successful attempts, such as impossible travel. + * @param string $id The unique identifier of the Radar attempt to update. + * @param string|null $challengeStatus Set to `"success"` to mark the challenge as completed. + * @param string|null $attemptStatus Set to `"success"` to mark the authentication attempt as successful. + * @return mixed + */ + public function updateAttempt( + string $id, + ?string $challengeStatus = null, + ?string $attemptStatus = null, + ?\WorkOS\RequestOptions $options = null, + ): mixed { + $body = array_filter([ + 'challenge_status' => $challengeStatus, + 'attempt_status' => $attemptStatus, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'PUT', + path: "radar/attempts/{$id}", + body: $body, + options: $options, + ); + return $response; + } + + /** + * Add an entry to a Radar list + * + * Add an entry to a Radar list. + * @param \WorkOS\Resource\RadarType $type The type of the Radar list (e.g. ip_address, domain, email). + * @param \WorkOS\Resource\RadarAction $action The list action indicating whether to add the entry to the allow or block list. + * @param string $entry The value to add to the list. Must match the format of the list type (e.g. a valid IP address for `ip_address`, a valid email for `email`). + * @return \WorkOS\Resource\RadarListEntryAlreadyPresentResponse + */ + public function addListEntry( + \WorkOS\Resource\RadarType $type, + \WorkOS\Resource\RadarAction $action, + string $entry, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\RadarListEntryAlreadyPresentResponse { + $body = [ + 'entry' => $entry, + ]; + $response = $this->client->request( + method: 'POST', + path: "radar/lists/{$type->value}/{$action->value}", + body: $body, + options: $options, + ); + return RadarListEntryAlreadyPresentResponse::fromArray($response); + } + + /** + * Remove an entry from a Radar list + * + * Remove an entry from a Radar list. + * @param \WorkOS\Resource\RadarType $type The type of the Radar list (e.g. ip_address, domain, email). + * @param \WorkOS\Resource\RadarAction $action The list action indicating whether to remove the entry from the allow or block list. + * @param string $entry The value to remove from the list. Must match an existing entry. + * @return void + */ + public function removeListEntry( + \WorkOS\Resource\RadarType $type, + \WorkOS\Resource\RadarAction $action, + string $entry, + ?\WorkOS\RequestOptions $options = null, + ): void { + $body = [ + 'entry' => $entry, + ]; + $this->client->request( + method: 'DELETE', + path: "radar/lists/{$type->value}/{$action->value}", + body: $body, + options: $options, + ); + } +} diff --git a/lib/Service/SSO.php b/lib/Service/SSO.php new file mode 100644 index 00000000..fd502431 --- /dev/null +++ b/lib/Service/SSO.php @@ -0,0 +1,252 @@ + + */ + public function listConnections( + ?string $before = null, + ?string $after = null, + ?int $limit = null, + ?\WorkOS\Resource\EventsOrder $order = null, + ?\WorkOS\Resource\ConnectionsConnectionType $connectionType = null, + ?string $domain = null, + ?string $organizationId = null, + ?string $search = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\PaginatedResponse { + $query = array_filter([ + 'before' => $before, + 'after' => $after, + 'limit' => $limit, + 'order' => $order?->value, + 'connection_type' => $connectionType?->value, + 'domain' => $domain, + 'organization_id' => $organizationId, + 'search' => $search, + ], fn ($v) => $v !== null); + return $this->client->requestPage( + method: 'GET', + path: 'connections', + query: $query, + modelClass: Connection::class, + options: $options, + ); + } + + /** + * Get a Connection + * + * Get the details of an existing connection. + * @param string $id Unique identifier for the Connection. + * @return \WorkOS\Resource\Connection + */ + public function getConnection( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\Connection { + $response = $this->client->request( + method: 'GET', + path: "connections/{$id}", + options: $options, + ); + return Connection::fromArray($response); + } + + /** + * Delete a Connection + * + * Permanently deletes an existing connection. It cannot be undone. + * @param string $id Unique identifier for the Connection. + * @return void + */ + public function deleteConnection( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): void { + $this->client->request( + method: 'DELETE', + path: "connections/{$id}", + options: $options, + ); + } + + /** + * Initiate SSO + * + * Initiates the single sign-on flow. + * @param array|null $providerScopes Additional OAuth scopes to request from the identity provider. Only applicable when using OAuth connections. + * @param array|null $providerQueryParams Key/value pairs of query parameters to pass to the OAuth provider. Only applicable when using OAuth connections. + * @param string|null $domain (deprecated) Deprecated. Use `connection` or `organization` instead. Used to initiate SSO for a connection by domain. The domain must be associated with a connection in your WorkOS environment. + * @param \WorkOS\Resource\SSOProvider|null $provider Used to initiate OAuth authentication with Google, Microsoft, GitHub, or Apple. + * @param string $redirectUri Where to redirect the user after they complete the authentication process. You must use one of the redirect URIs configured via the [Redirects](https://dashboard.workos.com/redirects) page on the dashboard. + * @param string|null $state An optional parameter that can be used to encode arbitrary information to help restore application state between redirects. If included, the redirect URI received from WorkOS will contain the exact `state` that was passed. + * @param string|null $connection Used to initiate SSO for a connection. The value should be a WorkOS connection ID. + * + * You can persist the WorkOS connection ID with application user or team identifiers. WorkOS will use the connection indicated by the connection parameter to direct the user to the corresponding IdP for authentication. + * @param string|null $organization Used to initiate SSO for an organization. The value should be a WorkOS organization ID. + * + * You can persist the WorkOS organization ID with application user or team identifiers. WorkOS will use the organization ID to determine the appropriate connection and the IdP to direct the user to for authentication. + * @param string|null $domainHint Can be used to pre-fill the domain field when initiating authentication with Microsoft OAuth or with a Google SAML connection type. + * @param string|null $loginHint Can be used to pre-fill the username/email address field of the IdP sign-in page for the user, if you know their username ahead of time. Currently supported for OAuth, OpenID Connect, Okta, and Entra ID connections. + * @param string|null $nonce A random string generated by the client that is used to mitigate replay attacks. + * @return \WorkOS\Resource\SSOAuthorizeUrlResponse + */ + public function getAuthorizationUrl( + string $redirectUri, + ?array $providerScopes = null, + ?array $providerQueryParams = null, + ?string $domain = null, + ?\WorkOS\Resource\SSOProvider $provider = null, + ?string $state = null, + ?string $connection = null, + ?string $organization = null, + ?string $domainHint = null, + ?string $loginHint = null, + ?string $nonce = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\SSOAuthorizeUrlResponse { + $query = array_filter([ + 'provider_scopes' => $providerScopes, + 'provider_query_params' => $providerQueryParams, + 'domain' => $domain, + 'provider' => $provider?->value, + 'redirect_uri' => $redirectUri, + 'state' => $state, + 'connection' => $connection, + 'organization' => $organization, + 'domain_hint' => $domainHint, + 'login_hint' => $loginHint, + 'nonce' => $nonce, + 'response_type' => 'code', + ], fn ($v) => $v !== null); + $query['client_id'] = $this->client->requireClientId(); + $response = $this->client->request( + method: 'GET', + path: 'sso/authorize', + query: $query, + options: $options, + ); + return SSOAuthorizeUrlResponse::fromArray($response); + } + + /** + * Logout Redirect + * + * Logout allows to sign out a user from your application by triggering the identity provider sign out flow. This `GET` endpoint should be a redirection, since the identity provider user will be identified in the browser session. + * + * Before redirecting to this endpoint, you need to generate a short-lived logout token using the [Logout Authorize](https://workos.com/docs/reference/sso/logout/authorize) endpoint. + * @param string $token The logout token returned from the [Logout Authorize](https://workos.com/docs/reference/sso/logout/authorize) endpoint. + * @return mixed + */ + public function getLogoutUrl( + string $token, + ?\WorkOS\RequestOptions $options = null, + ): mixed { + $query = [ + 'token' => $token, + ]; + $response = $this->client->request( + method: 'GET', + path: 'sso/logout', + query: $query, + options: $options, + ); + return $response; + } + + /** + * Logout Authorize + * + * You should call this endpoint from your server to generate a logout token which is required for the [Logout Redirect](https://workos.com/docs/reference/sso/logout) endpoint. + * @param string $profileId The unique ID of the profile to log out. + * @return \WorkOS\Resource\SSOLogoutAuthorizeResponse + */ + public function authorizeLogout( + string $profileId, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\SSOLogoutAuthorizeResponse { + $body = [ + 'profile_id' => $profileId, + ]; + $response = $this->client->request( + method: 'POST', + path: 'sso/logout/authorize', + body: $body, + options: $options, + ); + return SSOLogoutAuthorizeResponse::fromArray($response); + } + + /** + * Get a User Profile + * + * Exchange an access token for a user's [Profile](https://workos.com/docs/reference/sso/profile). Because this profile is returned in the [Get a Profile and Token endpoint](https://workos.com/docs/reference/sso/profile/get-profile-and-token) your application usually does not need to call this endpoint. It is available for any authentication flows that require an additional endpoint to retrieve a user's profile. + * @return \WorkOS\Resource\Profile + */ + public function getProfile( + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\Profile { + $response = $this->client->request( + method: 'GET', + path: 'sso/profile', + options: $options, + ); + return Profile::fromArray($response); + } + + /** + * Get a Profile and Token + * + * Get an access token along with the user [Profile](https://workos.com/docs/reference/sso/profile) using the code passed to your [Redirect URI](https://workos.com/docs/reference/sso/get-authorization-url/redirect-uri). + * @param string $code The authorization code received from the authorization callback. + * @return \WorkOS\Resource\SSOTokenResponse + */ + public function getProfileAndToken( + string $code, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\SSOTokenResponse { + $body = [ + 'code' => $code, + 'grant_type' => 'authorization_code', + ]; + $body['client_id'] = $this->client->requireClientId(); + $body['client_secret'] = $this->client->requireApiKey(); + $response = $this->client->request( + method: 'POST', + path: 'sso/token', + body: $body, + options: $options, + ); + return SSOTokenResponse::fromArray($response); + } +} diff --git a/lib/Service/UserManagement.php b/lib/Service/UserManagement.php new file mode 100644 index 00000000..56b4fd14 --- /dev/null +++ b/lib/Service/UserManagement.php @@ -0,0 +1,1377 @@ +client->request( + method: 'GET', + path: "sso/jwks/{$clientId}", + options: $options, + ); + return JwksResponse::fromArray($response); + } + + /** + * @param string $email + * @param string $password + * @param string|null $invitationToken + * @return \WorkOS\Resource\AuthenticateResponse + */ + public function authenticateWithPassword( + string $email, + string $password, + ?string $invitationToken = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\AuthenticateResponse { + $body = array_filter([ + 'grant_type' => 'password', + 'email' => $email, + 'password' => $password, + 'invitation_token' => $invitationToken, + ], fn ($v) => $v !== null); + $body['client_id'] = $this->client->requireClientId(); + $body['client_secret'] = $this->client->requireApiKey(); + + $response = $this->client->request( + method: 'POST', + path: 'user_management/authenticate', + body: $body, + options: $options, + ); + return AuthenticateResponse::fromArray($response); + } + + /** + * @param mixed|null $code + * @return \WorkOS\Resource\AuthenticateResponse + */ + public function authenticateWithCode( + mixed $code = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\AuthenticateResponse { + $body = array_filter([ + 'grant_type' => 'authorization_code', + 'code' => $code, + ], fn ($v) => $v !== null); + $body['client_id'] = $this->client->requireClientId(); + $body['client_secret'] = $this->client->requireApiKey(); + + $response = $this->client->request( + method: 'POST', + path: 'user_management/authenticate', + body: $body, + options: $options, + ); + return AuthenticateResponse::fromArray($response); + } + + /** + * @param string $refreshToken + * @param string|null $organizationId + * @return \WorkOS\Resource\AuthenticateResponse + */ + public function authenticateWithRefreshToken( + string $refreshToken, + ?string $organizationId = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\AuthenticateResponse { + $body = array_filter([ + 'grant_type' => 'refresh_token', + 'refresh_token' => $refreshToken, + 'organization_id' => $organizationId, + ], fn ($v) => $v !== null); + $body['client_id'] = $this->client->requireClientId(); + $body['client_secret'] = $this->client->requireApiKey(); + + $response = $this->client->request( + method: 'POST', + path: 'user_management/authenticate', + body: $body, + options: $options, + ); + return AuthenticateResponse::fromArray($response); + } + + /** + * @param mixed|null $code + * @param mixed|null $email + * @param mixed|null $invitationToken + * @return \WorkOS\Resource\AuthenticateResponse + */ + public function authenticateWithMagicAuth( + mixed $code = null, + mixed $email = null, + mixed $invitationToken = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\AuthenticateResponse { + $body = array_filter([ + 'grant_type' => 'urn:workos:oauth:grant-type:magic-auth:code', + 'code' => $code, + 'email' => $email, + 'invitation_token' => $invitationToken, + ], fn ($v) => $v !== null); + $body['client_id'] = $this->client->requireClientId(); + $body['client_secret'] = $this->client->requireApiKey(); + + $response = $this->client->request( + method: 'POST', + path: 'user_management/authenticate', + body: $body, + options: $options, + ); + return AuthenticateResponse::fromArray($response); + } + + /** + * @param mixed|null $code + * @param mixed|null $pendingAuthenticationToken + * @return \WorkOS\Resource\AuthenticateResponse + */ + public function authenticateWithEmailVerification( + mixed $code = null, + mixed $pendingAuthenticationToken = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\AuthenticateResponse { + $body = array_filter([ + 'grant_type' => 'urn:workos:oauth:grant-type:email-verification:code', + 'code' => $code, + 'pending_authentication_token' => $pendingAuthenticationToken, + ], fn ($v) => $v !== null); + $body['client_id'] = $this->client->requireClientId(); + $body['client_secret'] = $this->client->requireApiKey(); + + $response = $this->client->request( + method: 'POST', + path: 'user_management/authenticate', + body: $body, + options: $options, + ); + return AuthenticateResponse::fromArray($response); + } + + /** + * @param mixed|null $code + * @param mixed|null $pendingAuthenticationToken + * @param mixed|null $authenticationChallengeId + * @return \WorkOS\Resource\AuthenticateResponse + */ + public function authenticateWithTotp( + mixed $code = null, + mixed $pendingAuthenticationToken = null, + mixed $authenticationChallengeId = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\AuthenticateResponse { + $body = array_filter([ + 'grant_type' => 'urn:workos:oauth:grant-type:mfa-totp', + 'code' => $code, + 'pending_authentication_token' => $pendingAuthenticationToken, + 'authentication_challenge_id' => $authenticationChallengeId, + ], fn ($v) => $v !== null); + $body['client_id'] = $this->client->requireClientId(); + $body['client_secret'] = $this->client->requireApiKey(); + + $response = $this->client->request( + method: 'POST', + path: 'user_management/authenticate', + body: $body, + options: $options, + ); + return AuthenticateResponse::fromArray($response); + } + + /** + * @param mixed|null $pendingAuthenticationToken + * @param mixed|null $organizationId + * @return \WorkOS\Resource\AuthenticateResponse + */ + public function authenticateWithOrganizationSelection( + mixed $pendingAuthenticationToken = null, + mixed $organizationId = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\AuthenticateResponse { + $body = array_filter([ + 'grant_type' => 'urn:workos:oauth:grant-type:organization-selection', + 'pending_authentication_token' => $pendingAuthenticationToken, + 'organization_id' => $organizationId, + ], fn ($v) => $v !== null); + $body['client_id'] = $this->client->requireClientId(); + $body['client_secret'] = $this->client->requireApiKey(); + + $response = $this->client->request( + method: 'POST', + path: 'user_management/authenticate', + body: $body, + options: $options, + ); + return AuthenticateResponse::fromArray($response); + } + + /** + * @param mixed|null $deviceCode + * @return \WorkOS\Resource\AuthenticateResponse + */ + public function authenticateWithDeviceCode( + mixed $deviceCode = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\AuthenticateResponse { + $body = array_filter([ + 'grant_type' => 'urn:ietf:params:oauth:grant-type:device_code', + 'device_code' => $deviceCode, + ], fn ($v) => $v !== null); + $body['client_id'] = $this->client->requireClientId(); + + $response = $this->client->request( + method: 'POST', + path: 'user_management/authenticate', + body: $body, + options: $options, + ); + return AuthenticateResponse::fromArray($response); + } + + /** + * Get an authorization URL + * + * Generates an OAuth 2.0 authorization URL to authenticate a user with AuthKit or SSO. + * @param string|null $codeChallengeMethod The only valid PKCE code challenge method is `"S256"`. Required when specifying a `code_challenge`. + * @param string|null $codeChallenge Code challenge derived from the code verifier used for the PKCE flow. + * @param string|null $domainHint A domain hint for SSO connection lookup. + * @param string|null $connectionId The ID of an SSO connection to use for authentication. + * @param array|null $providerQueryParams Key/value pairs of query parameters to pass to the OAuth provider. + * @param array|null $providerScopes Additional OAuth scopes to request from the identity provider. + * @param string|null $invitationToken A token representing a user invitation to redeem during authentication. + * @param \WorkOS\Resource\UserManagementAuthenticationScreenHint|null $screenHint Used to specify which screen to display when the provider is `authkit`. Defaults to "sign-in". + * @param string|null $loginHint A hint to the authorization server about the login identifier the user might use. + * @param \WorkOS\Resource\UserManagementAuthenticationProvider|null $provider The OAuth provider to authenticate with (e.g., GoogleOAuth, MicrosoftOAuth, GitHubOAuth). + * @param string|null $prompt Controls the authentication flow behavior for the user. + * @param string|null $state An opaque value used to maintain state between the request and the callback. + * @param string|null $organizationId The ID of the organization to authenticate the user against. + * @param string $redirectUri The callback URI where the authorization code will be sent after authentication. + * @return mixed + */ + public function getAuthorizationUrl( + string $redirectUri, + ?string $codeChallengeMethod = null, + ?string $codeChallenge = null, + ?string $domainHint = null, + ?string $connectionId = null, + ?array $providerQueryParams = null, + ?array $providerScopes = null, + ?string $invitationToken = null, + ?\WorkOS\Resource\UserManagementAuthenticationScreenHint $screenHint = null, + ?string $loginHint = null, + ?\WorkOS\Resource\UserManagementAuthenticationProvider $provider = null, + ?string $prompt = null, + ?string $state = null, + ?string $organizationId = null, + ?\WorkOS\RequestOptions $options = null, + ): mixed { + $query = array_filter([ + 'code_challenge_method' => $codeChallengeMethod, + 'code_challenge' => $codeChallenge, + 'domain_hint' => $domainHint, + 'connection_id' => $connectionId, + 'provider_query_params' => $providerQueryParams, + 'provider_scopes' => $providerScopes, + 'invitation_token' => $invitationToken, + 'screen_hint' => $screenHint?->value, + 'login_hint' => $loginHint, + 'provider' => $provider?->value, + 'prompt' => $prompt, + 'state' => $state, + 'organization_id' => $organizationId, + 'redirect_uri' => $redirectUri, + 'response_type' => 'code', + ], fn ($v) => $v !== null); + $query['client_id'] = $this->client->requireClientId(); + $response = $this->client->request( + method: 'GET', + path: 'user_management/authorize', + query: $query, + options: $options, + ); + return $response; + } + + /** + * Get device authorization URL + * + * Initiates the CLI Auth flow by requesting a device code and verification URLs. This endpoint implements the OAuth 2.0 Device Authorization Flow ([RFC 8628](https://datatracker.ietf.org/doc/html/rfc8628)) and is designed for command-line applications or other devices with limited input capabilities. + * @param string $clientId The WorkOS client ID for your application. + * @return \WorkOS\Resource\DeviceAuthorizationResponse + */ + public function createDevice( + string $clientId, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\DeviceAuthorizationResponse { + $body = [ + 'client_id' => $clientId, + ]; + $response = $this->client->request( + method: 'POST', + path: 'user_management/authorize/device', + body: $body, + options: $options, + ); + return DeviceAuthorizationResponse::fromArray($response); + } + + /** + * Logout + * + * Logout a user from the current [session](https://workos.com/docs/reference/authkit/session). + * @param string $sessionId The ID of the session to revoke. This can be extracted from the `sid` claim of the access token. + * @param string|null $returnTo The URL to redirect the user to after session revocation. + * @return mixed + */ + public function getLogoutUrl( + string $sessionId, + ?string $returnTo = null, + ?\WorkOS\RequestOptions $options = null, + ): mixed { + $query = array_filter([ + 'session_id' => $sessionId, + 'return_to' => $returnTo, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'GET', + path: 'user_management/sessions/logout', + query: $query, + options: $options, + ); + return $response; + } + + /** + * Revoke Session + * + * Revoke a [user session](https://workos.com/docs/reference/authkit/session). + * @param string $sessionId The ID of the session to revoke. This can be extracted from the `sid` claim of the access token. + * @param string|null $returnTo The URL to redirect the user to after session revocation. + * @return mixed + */ + public function revokeSession( + string $sessionId, + ?string $returnTo = null, + ?\WorkOS\RequestOptions $options = null, + ): mixed { + $body = array_filter([ + 'session_id' => $sessionId, + 'return_to' => $returnTo, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'POST', + path: 'user_management/sessions/revoke', + body: $body, + options: $options, + ); + return $response; + } + + /** + * Create a CORS origin + * + * Creates a new CORS origin for the current environment. CORS origins allow browser-based applications to make requests to the WorkOS API. + * @param string $origin The origin URL to allow for CORS requests. + * @return \WorkOS\Resource\CORSOriginResponse + */ + public function createCorsOrigin( + string $origin, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\CORSOriginResponse { + $body = [ + 'origin' => $origin, + ]; + $response = $this->client->request( + method: 'POST', + path: 'user_management/cors_origins', + body: $body, + options: $options, + ); + return CORSOriginResponse::fromArray($response); + } + + /** + * Get an email verification code + * + * Get the details of an existing email verification code that can be used to send an email to a user for verification. + * @param string $id The ID of the email verification code. + * @return \WorkOS\Resource\EmailVerification + */ + public function getEmailVerification( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\EmailVerification { + $response = $this->client->request( + method: 'GET', + path: "user_management/email_verification/{$id}", + options: $options, + ); + return EmailVerification::fromArray($response); + } + + /** + * Create a password reset token + * + * Creates a one-time token that can be used to reset a user's password. + * @param string $email The email address of the user requesting a password reset. + * @return \WorkOS\Resource\PasswordReset + */ + public function resetPassword( + string $email, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\PasswordReset { + $body = [ + 'email' => $email, + ]; + $response = $this->client->request( + method: 'POST', + path: 'user_management/password_reset', + body: $body, + options: $options, + ); + return PasswordReset::fromArray($response); + } + + /** + * Reset the password + * + * Sets a new password using the `token` query parameter from the link that the user received. Successfully resetting the password will verify a user's email, if it hasn't been verified yet. + * @param string $token The password reset token. + * @param string $newPassword The new password to set for the user. + * @return \WorkOS\Resource\ResetPasswordResponse + */ + public function confirmPasswordReset( + string $token, + string $newPassword, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\ResetPasswordResponse { + $body = [ + 'token' => $token, + 'new_password' => $newPassword, + ]; + $response = $this->client->request( + method: 'POST', + path: 'user_management/password_reset/confirm', + body: $body, + options: $options, + ); + return ResetPasswordResponse::fromArray($response); + } + + /** + * Get a password reset token + * + * Get the details of an existing password reset token that can be used to reset a user's password. + * @param string $id The ID of the password reset token. + * @return \WorkOS\Resource\PasswordReset + */ + public function getPasswordReset( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\PasswordReset { + $response = $this->client->request( + method: 'GET', + path: "user_management/password_reset/{$id}", + options: $options, + ); + return PasswordReset::fromArray($response); + } + + /** + * List users + * + * Get a list of all of your existing users matching the criteria specified. + * @param string|null $before An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `before="obj_123"` to fetch a new batch of objects before `"obj_123"`. + * @param string|null $after An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `after="obj_123"` to fetch a new batch of objects after `"obj_123"`. + * @param int|null $limit Upper limit on the number of objects to return, between `1` and `100`. Defaults to 10. + * @param \WorkOS\Resource\EventsOrder|null $order Order the results by the creation time. Supported values are `"asc"` (ascending), `"desc"` (descending), and `"normal"` (descending with reversed cursor semantics where `before` fetches older records and `after` fetches newer records). Defaults to descending. Defaults to "desc". + * @param string|null $organization (deprecated) Filter users by the organization they are a member of. Deprecated in favor of `organization_id`. + * @param string|null $organizationId Filter users by the organization they are a member of. + * @param string|null $email Filter users by their email address. + * @return \WorkOS\PaginatedResponse<\WorkOS\Resource\User> + */ + public function listUsers( + ?string $before = null, + ?string $after = null, + ?int $limit = null, + ?\WorkOS\Resource\EventsOrder $order = null, + ?string $organization = null, + ?string $organizationId = null, + ?string $email = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\PaginatedResponse { + $query = array_filter([ + 'before' => $before, + 'after' => $after, + 'limit' => $limit, + 'order' => $order?->value, + 'organization' => $organization, + 'organization_id' => $organizationId, + 'email' => $email, + ], fn ($v) => $v !== null); + return $this->client->requestPage( + method: 'GET', + path: 'user_management/users', + query: $query, + modelClass: User::class, + options: $options, + ); + } + + /** + * Create a user + * + * Create a new user in the current environment. + * @param string $email The email address of the user. + * @param string|null $password The password to set for the user. Mutually exclusive with `password_hash` and `password_hash_type`. + * @param string|null $passwordHash The hashed password to set for the user. Mutually exclusive with `password`. + * @param \WorkOS\Resource\CreateUserPasswordHashType|null $passwordHashType The algorithm originally used to hash the password, used when providing a `password_hash`. + * @param string|null $firstName The first name of the user. + * @param string|null $lastName The last name of the user. + * @param bool|null $emailVerified Whether the user's email has been verified. + * @param array|null $metadata Object containing metadata key/value pairs associated with the user. + * @param string|null $externalId The external ID of the user. + * @return \WorkOS\Resource\User + */ + public function createUser( + string $email, + ?string $password = null, + ?string $passwordHash = null, + ?\WorkOS\Resource\CreateUserPasswordHashType $passwordHashType = null, + ?string $firstName = null, + ?string $lastName = null, + ?bool $emailVerified = null, + ?array $metadata = null, + ?string $externalId = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\User { + $body = array_filter([ + 'email' => $email, + 'password' => $password, + 'password_hash' => $passwordHash, + 'password_hash_type' => $passwordHashType?->value, + 'first_name' => $firstName, + 'last_name' => $lastName, + 'email_verified' => $emailVerified, + 'metadata' => $metadata, + 'external_id' => $externalId, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'POST', + path: 'user_management/users', + body: $body, + options: $options, + ); + return User::fromArray($response); + } + + /** + * Get a user by external ID + * + * Get the details of an existing user by an [external identifier](https://workos.com/docs/authkit/metadata/external-identifiers). + * @param string $externalId The external ID of the user. + * @return \WorkOS\Resource\User + */ + public function getUserByExternalId( + string $externalId, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\User { + $response = $this->client->request( + method: 'GET', + path: "user_management/users/external_id/{$externalId}", + options: $options, + ); + return User::fromArray($response); + } + + /** + * Get a user + * + * Get the details of an existing user. + * @param string $id The unique ID of the user. + * @return \WorkOS\Resource\User + */ + public function getUser( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\User { + $response = $this->client->request( + method: 'GET', + path: "user_management/users/{$id}", + options: $options, + ); + return User::fromArray($response); + } + + /** + * Update a user + * + * Updates properties of a user. The omitted properties will be left unchanged. + * @param string $id The unique ID of the user. + * @param string|null $email The email address of the user. + * @param string|null $firstName The first name of the user. + * @param string|null $lastName The last name of the user. + * @param bool|null $emailVerified Whether the user's email has been verified. + * @param string|null $password The password to set for the user. + * @param string|null $passwordHash The hashed password to set for the user. Mutually exclusive with `password`. + * @param \WorkOS\Resource\CreateUserPasswordHashType|null $passwordHashType The algorithm originally used to hash the password, used when providing a `password_hash`. + * @param array|null $metadata Object containing metadata key/value pairs associated with the user. + * @param string|null $externalId The external ID of the user. + * @param string|null $locale The user's preferred locale. + * @return \WorkOS\Resource\User + */ + public function updateUser( + string $id, + ?string $email = null, + ?string $firstName = null, + ?string $lastName = null, + ?bool $emailVerified = null, + ?string $password = null, + ?string $passwordHash = null, + ?\WorkOS\Resource\CreateUserPasswordHashType $passwordHashType = null, + ?array $metadata = null, + ?string $externalId = null, + ?string $locale = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\User { + $body = array_filter([ + 'email' => $email, + 'first_name' => $firstName, + 'last_name' => $lastName, + 'email_verified' => $emailVerified, + 'password' => $password, + 'password_hash' => $passwordHash, + 'password_hash_type' => $passwordHashType?->value, + 'metadata' => $metadata, + 'external_id' => $externalId, + 'locale' => $locale, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'PUT', + path: "user_management/users/{$id}", + body: $body, + options: $options, + ); + return User::fromArray($response); + } + + /** + * Delete a user + * + * Permanently deletes a user in the current environment. It cannot be undone. + * @param string $id The unique ID of the user. + * @return void + */ + public function deleteUser( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): void { + $this->client->request( + method: 'DELETE', + path: "user_management/users/{$id}", + options: $options, + ); + } + + /** + * Confirm email change + * + * Confirms an email change using the one-time code received by the user. + * @param string $id The unique ID of the user. + * @param string $code The one-time code used to confirm the email change. + * @return \WorkOS\Resource\EmailChangeConfirmation + */ + public function confirmEmailChange( + string $id, + string $code, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\EmailChangeConfirmation { + $body = [ + 'code' => $code, + ]; + $response = $this->client->request( + method: 'POST', + path: "user_management/users/{$id}/email_change/confirm", + body: $body, + options: $options, + ); + return EmailChangeConfirmation::fromArray($response); + } + + /** + * Send email change code + * + * Sends an email that contains a one-time code used to change a user's email address. + * @param string $id The unique ID of the user. + * @param string $newEmail The new email address to change to. + * @return \WorkOS\Resource\EmailChange + */ + public function sendEmailChange( + string $id, + string $newEmail, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\EmailChange { + $body = [ + 'new_email' => $newEmail, + ]; + $response = $this->client->request( + method: 'POST', + path: "user_management/users/{$id}/email_change/send", + body: $body, + options: $options, + ); + return EmailChange::fromArray($response); + } + + /** + * Verify email + * + * Verifies an email address using the one-time code received by the user. + * @param string $id The ID of the user. + * @param string $code The one-time email verification code. + * @return \WorkOS\Resource\VerifyEmailResponse + */ + public function verifyEmail( + string $id, + string $code, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\VerifyEmailResponse { + $body = [ + 'code' => $code, + ]; + $response = $this->client->request( + method: 'POST', + path: "user_management/users/{$id}/email_verification/confirm", + body: $body, + options: $options, + ); + return VerifyEmailResponse::fromArray($response); + } + + /** + * Send verification email + * + * Sends an email that contains a one-time code used to verify a user’s email address. + * @param string $id The ID of the user. + * @return \WorkOS\Resource\SendVerificationEmailResponse + */ + public function sendVerificationEmail( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\SendVerificationEmailResponse { + $response = $this->client->request( + method: 'POST', + path: "user_management/users/{$id}/email_verification/send", + options: $options, + ); + return SendVerificationEmailResponse::fromArray($response); + } + + /** + * Get user identities + * + * Get a list of identities associated with the user. A user can have multiple associated identities after going through [identity linking](https://workos.com/docs/authkit/identity-linking). Currently only OAuth identities are supported. More provider types may be added in the future. + * @param string $id The unique ID of the user. + * @return array + */ + public function getUserIdentities( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): array { + $response = $this->client->request( + method: 'GET', + path: "user_management/users/{$id}/identities", + options: $options, + ); + return array_map(fn ($item) => UserIdentitiesGetItem::fromArray($item), $response); + } + + /** + * List sessions + * + * Get a list of all active sessions for a specific user. + * @param string $id The ID of the user. + * @param string|null $before An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `before="obj_123"` to fetch a new batch of objects before `"obj_123"`. + * @param string|null $after An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `after="obj_123"` to fetch a new batch of objects after `"obj_123"`. + * @param int|null $limit Upper limit on the number of objects to return, between `1` and `100`. Defaults to 10. + * @param \WorkOS\Resource\EventsOrder|null $order Order the results by the creation time. Supported values are `"asc"` (ascending), `"desc"` (descending), and `"normal"` (descending with reversed cursor semantics where `before` fetches older records and `after` fetches newer records). Defaults to descending. Defaults to "desc". + * @return \WorkOS\PaginatedResponse<\WorkOS\Resource\UserSessionsListItem> + */ + public function listSessions( + string $id, + ?string $before = null, + ?string $after = null, + ?int $limit = null, + ?\WorkOS\Resource\EventsOrder $order = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\PaginatedResponse { + $query = array_filter([ + 'before' => $before, + 'after' => $after, + 'limit' => $limit, + 'order' => $order?->value, + ], fn ($v) => $v !== null); + return $this->client->requestPage( + method: 'GET', + path: "user_management/users/{$id}/sessions", + query: $query, + modelClass: UserSessionsListItem::class, + options: $options, + ); + } + + /** + * List invitations + * + * Get a list of all of invitations matching the criteria specified. + * @param string|null $before An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `before="obj_123"` to fetch a new batch of objects before `"obj_123"`. + * @param string|null $after An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `after="obj_123"` to fetch a new batch of objects after `"obj_123"`. + * @param int|null $limit Upper limit on the number of objects to return, between `1` and `100`. Defaults to 10. + * @param \WorkOS\Resource\EventsOrder|null $order Order the results by the creation time. Supported values are `"asc"` (ascending), `"desc"` (descending), and `"normal"` (descending with reversed cursor semantics where `before` fetches older records and `after` fetches newer records). Defaults to descending. Defaults to "desc". + * @param string|null $organizationId The ID of the [organization](https://workos.com/docs/reference/organization) that the recipient will join. + * @param string|null $email The email address of the recipient. + * @return \WorkOS\PaginatedResponse<\WorkOS\Resource\UserInvite> + */ + public function listInvitations( + ?string $before = null, + ?string $after = null, + ?int $limit = null, + ?\WorkOS\Resource\EventsOrder $order = null, + ?string $organizationId = null, + ?string $email = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\PaginatedResponse { + $query = array_filter([ + 'before' => $before, + 'after' => $after, + 'limit' => $limit, + 'order' => $order?->value, + 'organization_id' => $organizationId, + 'email' => $email, + ], fn ($v) => $v !== null); + return $this->client->requestPage( + method: 'GET', + path: 'user_management/invitations', + query: $query, + modelClass: UserInvite::class, + options: $options, + ); + } + + /** + * Send an invitation + * + * Sends an invitation email to the recipient. + * @param string $email The email address of the recipient. + * @param string|null $organizationId The ID of the [organization](https://workos.com/docs/reference/organization) that the recipient will join. + * @param string|null $roleSlug The [role](https://workos.com/docs/authkit/roles) that the recipient will receive when they join the organization in the invitation. + * @param int|null $expiresInDays How many days the invitations will be valid for. Must be between 1 and 30 days. Defaults to 7 days if not specified. + * @param string|null $inviterUserId The ID of the [user](https://workos.com/docs/reference/authkit/user) who invites the recipient. The invitation email will mention the name of this user. + * @param \WorkOS\Resource\CreateUserInviteOptionsLocale|null $locale The locale to use when rendering the invitation email. See [supported locales](https://workos.com/docs/authkit/hosted-ui/localization). + * @return \WorkOS\Resource\UserInvite + */ + public function sendInvitation( + string $email, + ?string $organizationId = null, + ?string $roleSlug = null, + ?int $expiresInDays = null, + ?string $inviterUserId = null, + ?\WorkOS\Resource\CreateUserInviteOptionsLocale $locale = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\UserInvite { + $body = array_filter([ + 'email' => $email, + 'organization_id' => $organizationId, + 'role_slug' => $roleSlug, + 'expires_in_days' => $expiresInDays, + 'inviter_user_id' => $inviterUserId, + 'locale' => $locale?->value, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'POST', + path: 'user_management/invitations', + body: $body, + options: $options, + ); + return UserInvite::fromArray($response); + } + + /** + * Find an invitation by token + * + * Retrieve an existing invitation using the token. + * @param string $token The token used to accept the invitation. + * @return \WorkOS\Resource\UserInvite + */ + public function findInvitationByToken( + string $token, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\UserInvite { + $response = $this->client->request( + method: 'GET', + path: "user_management/invitations/by_token/{$token}", + options: $options, + ); + return UserInvite::fromArray($response); + } + + /** + * Get an invitation + * + * Get the details of an existing invitation. + * @param string $id The unique ID of the invitation. + * @return \WorkOS\Resource\UserInvite + */ + public function getInvitation( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\UserInvite { + $response = $this->client->request( + method: 'GET', + path: "user_management/invitations/{$id}", + options: $options, + ); + return UserInvite::fromArray($response); + } + + /** + * Accept an invitation + * + * Accepts an invitation and, if linked to an organization, activates the user's membership in that organization. + * @param string $id The unique ID of the invitation. + * @return \WorkOS\Resource\Invitation + */ + public function acceptInvitation( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\Invitation { + $response = $this->client->request( + method: 'POST', + path: "user_management/invitations/{$id}/accept", + options: $options, + ); + return Invitation::fromArray($response); + } + + /** + * Resend an invitation + * + * Resends an invitation email to the recipient. The invitation must be in a pending state. + * @param string $id The unique ID of the invitation. + * @param \WorkOS\Resource\CreateUserInviteOptionsLocale|null $locale The locale to use when rendering the invitation email. See [supported locales](https://workos.com/docs/authkit/hosted-ui/localization). + * @return \WorkOS\Resource\UserInvite + */ + public function resendInvitation( + string $id, + ?\WorkOS\Resource\CreateUserInviteOptionsLocale $locale = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\UserInvite { + $body = array_filter([ + 'locale' => $locale?->value, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'POST', + path: "user_management/invitations/{$id}/resend", + body: $body, + options: $options, + ); + return UserInvite::fromArray($response); + } + + /** + * Revoke an invitation + * + * Revokes an existing invitation. + * @param string $id The unique ID of the invitation. + * @return \WorkOS\Resource\Invitation + */ + public function revokeInvitation( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\Invitation { + $response = $this->client->request( + method: 'POST', + path: "user_management/invitations/{$id}/revoke", + options: $options, + ); + return Invitation::fromArray($response); + } + + /** + * Update JWT template + * + * Update the JWT template for the current environment. + * @param string $content The JWT template content as a Liquid template string. + * @return \WorkOS\Resource\JWTTemplateResponse + */ + public function updateJWTTemplate( + string $content, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\JWTTemplateResponse { + $body = [ + 'content' => $content, + ]; + $response = $this->client->request( + method: 'PUT', + path: 'user_management/jwt_template', + body: $body, + options: $options, + ); + return JWTTemplateResponse::fromArray($response); + } + + /** + * Create a Magic Auth code + * + * Creates a one-time authentication code that can be sent to the user's email address. The code expires in 10 minutes. To verify the code, [authenticate the user with Magic Auth](https://workos.com/docs/reference/authkit/authentication/magic-auth). + * @param string $email The email address to send the magic code to. + * @param string|null $invitationToken The invitation token to associate with this magic code. + * @return \WorkOS\Resource\MagicAuth + */ + public function createMagicAuth( + string $email, + ?string $invitationToken = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\MagicAuth { + $body = array_filter([ + 'email' => $email, + 'invitation_token' => $invitationToken, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'POST', + path: 'user_management/magic_auth', + body: $body, + options: $options, + ); + return MagicAuth::fromArray($response); + } + + /** + * Get Magic Auth code details + * + * Get the details of an existing [Magic Auth](https://workos.com/docs/reference/authkit/magic-auth) code that can be used to send an email to a user for authentication. + * @param string $id The unique ID of the Magic Auth code. + * @return \WorkOS\Resource\MagicAuth + */ + public function getMagicAuth( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\MagicAuth { + $response = $this->client->request( + method: 'GET', + path: "user_management/magic_auth/{$id}", + options: $options, + ); + return MagicAuth::fromArray($response); + } + + /** + * List organization memberships + * + * Get a list of all organization memberships matching the criteria specified. At least one of `user_id` or `organization_id` must be provided. By default only active memberships are returned. Use the `statuses` parameter to filter by other statuses. + * @param string|null $before An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `before="obj_123"` to fetch a new batch of objects before `"obj_123"`. + * @param string|null $after An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `after="obj_123"` to fetch a new batch of objects after `"obj_123"`. + * @param int|null $limit Upper limit on the number of objects to return, between `1` and `100`. Defaults to 10. + * @param \WorkOS\Resource\EventsOrder|null $order Order the results by the creation time. Supported values are `"asc"` (ascending), `"desc"` (descending), and `"normal"` (descending with reversed cursor semantics where `before` fetches older records and `after` fetches newer records). Defaults to descending. Defaults to "desc". + * @param string|null $organizationId The ID of the [organization](https://workos.com/docs/reference/organization) which the user belongs to. + * @param array<\WorkOS\Resource\OrganizationMembershipStatus>|null $statuses Filter by the status of the organization membership. Array including any of `active`, `inactive`, or `pending`. + * @param string|null $userId The ID of the [user](https://workos.com/docs/reference/authkit/user). + * @return \WorkOS\PaginatedResponse<\WorkOS\Resource\UserOrganizationMembership> + */ + public function listOrganizationMemberships( + ?string $before = null, + ?string $after = null, + ?int $limit = null, + ?\WorkOS\Resource\EventsOrder $order = null, + ?string $organizationId = null, + ?array $statuses = null, + ?string $userId = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\PaginatedResponse { + $query = array_filter([ + 'before' => $before, + 'after' => $after, + 'limit' => $limit, + 'order' => $order?->value, + 'organization_id' => $organizationId, + 'statuses' => $statuses, + 'user_id' => $userId, + ], fn ($v) => $v !== null); + return $this->client->requestPage( + method: 'GET', + path: 'user_management/organization_memberships', + query: $query, + modelClass: UserOrganizationMembership::class, + options: $options, + ); + } + + /** + * Create an organization membership + * + * Creates a new `active` organization membership for the given organization and user. + * + * Calling this API with an organization and user that match an `inactive` organization membership will activate the membership with the specified role(s). + * @param string $userId The ID of the [user](https://workos.com/docs/reference/authkit/user). + * @param string $organizationId The ID of the [organization](https://workos.com/docs/reference/organization) which the user belongs to. + * @param string|null $roleSlug A single role identifier. Defaults to `member` or the explicit default role. Mutually exclusive with `role_slugs`. + * @param array|null $roleSlugs An array of role identifiers. Limited to one role when Multiple Roles is disabled. Mutually exclusive with `role_slug`. + * @return \WorkOS\Resource\OrganizationMembership + */ + public function createOrganizationMembership( + string $userId, + string $organizationId, + ?string $roleSlug = null, + ?array $roleSlugs = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\OrganizationMembership { + $body = array_filter([ + 'user_id' => $userId, + 'organization_id' => $organizationId, + 'role_slug' => $roleSlug, + 'role_slugs' => $roleSlugs, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'POST', + path: 'user_management/organization_memberships', + body: $body, + options: $options, + ); + return OrganizationMembership::fromArray($response); + } + + /** + * Get an organization membership + * + * Get the details of an existing organization membership. + * @param string $id The unique ID of the organization membership. + * @return \WorkOS\Resource\UserOrganizationMembership + */ + public function getOrganizationMembership( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\UserOrganizationMembership { + $response = $this->client->request( + method: 'GET', + path: "user_management/organization_memberships/{$id}", + options: $options, + ); + return UserOrganizationMembership::fromArray($response); + } + + /** + * Update an organization membership + * + * Update the details of an existing organization membership. + * @param string $id The unique ID of the organization membership. + * @param string|null $roleSlug A single role identifier. Defaults to `member` or the explicit default role. Mutually exclusive with `role_slugs`. + * @param array|null $roleSlugs An array of role identifiers. Limited to one role when Multiple Roles is disabled. Mutually exclusive with `role_slug`. + * @return \WorkOS\Resource\UserOrganizationMembership + */ + public function updateOrganizationMembership( + string $id, + ?string $roleSlug = null, + ?array $roleSlugs = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\UserOrganizationMembership { + $body = array_filter([ + 'role_slug' => $roleSlug, + 'role_slugs' => $roleSlugs, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'PUT', + path: "user_management/organization_memberships/{$id}", + body: $body, + options: $options, + ); + return UserOrganizationMembership::fromArray($response); + } + + /** + * Delete an organization membership + * + * Permanently deletes an existing organization membership. It cannot be undone. + * @param string $id The unique ID of the organization membership. + * @return void + */ + public function deleteOrganizationMembership( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): void { + $this->client->request( + method: 'DELETE', + path: "user_management/organization_memberships/{$id}", + options: $options, + ); + } + + /** + * Deactivate an organization membership + * + * Deactivates an `active` organization membership. Emits an [organization_membership.updated](https://workos.com/docs/events/organization-membership) event upon successful deactivation. + * + * - Deactivating an `inactive` membership is a no-op and does not emit an event. + * - Deactivating a `pending` membership returns an error. This membership should be [deleted](https://workos.com/docs/reference/authkit/organization-membership/delete) instead. + * + * See the [membership management documentation](https://workos.com/docs/authkit/users-organizations/organizations/membership-management) for additional details. + * @param string $id The unique ID of the organization membership. + * @return \WorkOS\Resource\OrganizationMembership + */ + public function deactivateOrganizationMembership( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\OrganizationMembership { + $response = $this->client->request( + method: 'PUT', + path: "user_management/organization_memberships/{$id}/deactivate", + options: $options, + ); + return OrganizationMembership::fromArray($response); + } + + /** + * Reactivate an organization membership + * + * Reactivates an `inactive` organization membership, retaining the pre-existing role(s). Emits an [organization_membership.updated](https://workos.com/docs/events/organization-membership) event upon successful reactivation. + * + * - Reactivating an `active` membership is a no-op and does not emit an event. + * - Reactivating a `pending` membership returns an error. The user needs to [accept the invitation](https://workos.com/docs/authkit/invitations) instead. + * + * See the [membership management documentation](https://workos.com/docs/authkit/users-organizations/organizations/membership-management) for additional details. + * @param string $id The unique ID of the organization membership. + * @return \WorkOS\Resource\UserOrganizationMembership + */ + public function reactivateOrganizationMembership( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\UserOrganizationMembership { + $response = $this->client->request( + method: 'PUT', + path: "user_management/organization_memberships/{$id}/reactivate", + options: $options, + ); + return UserOrganizationMembership::fromArray($response); + } + + /** + * Create a redirect URI + * + * Creates a new redirect URI for an environment. + * @param string $uri The redirect URI to create. + * @return \WorkOS\Resource\RedirectUri + */ + public function createRedirectUri( + string $uri, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\RedirectUri { + $body = [ + 'uri' => $uri, + ]; + $response = $this->client->request( + method: 'POST', + path: 'user_management/redirect_uris', + body: $body, + options: $options, + ); + return RedirectUri::fromArray($response); + } + + /** + * List authorized applications + * + * Get a list of all Connect applications that the user has authorized. + * @param string $userId The ID of the user. + * @param string|null $before An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `before="obj_123"` to fetch a new batch of objects before `"obj_123"`. + * @param string|null $after An object ID that defines your place in the list. When the ID is not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with `"obj_123"`, your subsequent call can include `after="obj_123"` to fetch a new batch of objects after `"obj_123"`. + * @param int|null $limit Upper limit on the number of objects to return, between `1` and `100`. Defaults to 10. + * @param \WorkOS\Resource\EventsOrder|null $order Order the results by the creation time. Supported values are `"asc"` (ascending), `"desc"` (descending), and `"normal"` (descending with reversed cursor semantics where `before` fetches older records and `after` fetches newer records). Defaults to descending. Defaults to "desc". + * @return \WorkOS\PaginatedResponse<\WorkOS\Resource\AuthorizedConnectApplicationListData> + */ + public function listUserAuthorizedApplications( + string $userId, + ?string $before = null, + ?string $after = null, + ?int $limit = null, + ?\WorkOS\Resource\EventsOrder $order = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\PaginatedResponse { + $query = array_filter([ + 'before' => $before, + 'after' => $after, + 'limit' => $limit, + 'order' => $order?->value, + ], fn ($v) => $v !== null); + return $this->client->requestPage( + method: 'GET', + path: "user_management/users/{$userId}/authorized_applications", + query: $query, + modelClass: AuthorizedConnectApplicationListData::class, + options: $options, + ); + } + + /** + * Delete an authorized application + * + * Delete an existing Authorized Connect Application. + * @param string $applicationId The ID or client ID of the application. + * @param string $userId The ID of the user. + * @return void + */ + public function deleteUserAuthorizedApplication( + string $applicationId, + string $userId, + ?\WorkOS\RequestOptions $options = null, + ): void { + $this->client->request( + method: 'DELETE', + path: "user_management/users/{$userId}/authorized_applications/{$applicationId}", + options: $options, + ); + } +} diff --git a/lib/Service/Webhooks.php b/lib/Service/Webhooks.php new file mode 100644 index 00000000..068e532d --- /dev/null +++ b/lib/Service/Webhooks.php @@ -0,0 +1,124 @@ + + */ + public function listWebhookEndpoints( + ?string $before = null, + ?string $after = null, + ?int $limit = null, + ?\WorkOS\Resource\EventsOrder $order = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\PaginatedResponse { + $query = array_filter([ + 'before' => $before, + 'after' => $after, + 'limit' => $limit, + 'order' => $order?->value, + ], fn ($v) => $v !== null); + return $this->client->requestPage( + method: 'GET', + path: 'webhook_endpoints', + query: $query, + modelClass: WebhookEndpointJson::class, + options: $options, + ); + } + + /** + * Create a Webhook Endpoint + * + * Create a new webhook endpoint to receive event notifications. + * @param string $endpointUrl The HTTPS URL where webhooks will be sent. + * @param array<\WorkOS\Resource\CreateWebhookEndpointEvents> $events The events that the Webhook Endpoint is subscribed to. + * @return \WorkOS\Resource\WebhookEndpointJson + */ + public function createWebhookEndpoints( + string $endpointUrl, + array $events, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\WebhookEndpointJson { + $body = [ + 'endpoint_url' => $endpointUrl, + 'events' => $events, + ]; + $response = $this->client->request( + method: 'POST', + path: 'webhook_endpoints', + body: $body, + options: $options, + ); + return WebhookEndpointJson::fromArray($response); + } + + /** + * Update a Webhook Endpoint + * + * Update the properties of an existing webhook endpoint. + * @param string $id Unique identifier of the Webhook Endpoint. + * @param string|null $endpointUrl The HTTPS URL where webhooks will be sent. + * @param \WorkOS\Resource\WebhookEndpointJsonStatus|null $status Whether the Webhook Endpoint is enabled or disabled. + * @param array<\WorkOS\Resource\CreateWebhookEndpointEvents>|null $events The events that the Webhook Endpoint is subscribed to. + * @return \WorkOS\Resource\WebhookEndpointJson + */ + public function updateWebhookEndpoint( + string $id, + ?string $endpointUrl = null, + ?\WorkOS\Resource\WebhookEndpointJsonStatus $status = null, + ?array $events = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\WebhookEndpointJson { + $body = array_filter([ + 'endpoint_url' => $endpointUrl, + 'status' => $status?->value, + 'events' => $events, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'PATCH', + path: "webhook_endpoints/{$id}", + body: $body, + options: $options, + ); + return WebhookEndpointJson::fromArray($response); + } + + /** + * Delete a Webhook Endpoint + * + * Delete an existing webhook endpoint. + * @param string $id Unique identifier of the Webhook Endpoint. + * @return void + */ + public function deleteWebhookEndpoint( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): void { + $this->client->request( + method: 'DELETE', + path: "webhook_endpoints/{$id}", + options: $options, + ); + } +} diff --git a/lib/Service/Widgets.php b/lib/Service/Widgets.php new file mode 100644 index 00000000..7c284923 --- /dev/null +++ b/lib/Service/Widgets.php @@ -0,0 +1,46 @@ +|null $scopes The scopes to grant the widget session. + * @return \WorkOS\Resource\WidgetSessionTokenResponse + */ + public function createToken( + string $organizationId, + ?string $userId = null, + ?array $scopes = null, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\WidgetSessionTokenResponse { + $body = array_filter([ + 'organization_id' => $organizationId, + 'user_id' => $userId, + 'scopes' => $scopes, + ], fn ($v) => $v !== null); + $response = $this->client->request( + method: 'POST', + path: 'widgets/token', + body: $body, + options: $options, + ); + return WidgetSessionTokenResponse::fromArray($response); + } +} diff --git a/lib/Session/HaliteSessionEncryption.php b/lib/Session/HaliteSessionEncryption.php deleted file mode 100644 index 90d368fe..00000000 --- a/lib/Session/HaliteSessionEncryption.php +++ /dev/null @@ -1,119 +0,0 @@ - $data, - 'expires_at' => $expiresAt - ]; - - $key = $this->deriveKey($password); - $encrypted = SymmetricCrypto::encrypt( - new HiddenString(json_encode($payload)), - $key - ); - - return base64_encode($encrypted); - } catch (\Exception $e) { - throw new UnexpectedValueException( - "Failed to seal session: " . $e->getMessage() - ); - } - } - - /** - * Decrypts and unseals session data with TTL validation. - * - * @param string $sealed Sealed session string - * @param string $password Decryption password - * - * @return array Unsealed session data - * @throws \WorkOS\Exception\UnexpectedValueException - */ - public function unseal(string $sealed, string $password): array - { - try { - $key = $this->deriveKey($password); - $encrypted = base64_decode($sealed); - - $decryptedHiddenString = SymmetricCrypto::decrypt($encrypted, $key); - $decrypted = $decryptedHiddenString->getString(); - $payload = json_decode($decrypted, true); - - if (!isset($payload['expires_at']) || !isset($payload['data'])) { - throw new UnexpectedValueException("Invalid session payload"); - } - - if (time() > $payload['expires_at']) { - throw new UnexpectedValueException("Session has expired"); - } - - return $payload['data']; - } catch (UnexpectedValueException $e) { - // Re-throw our exceptions - throw $e; - } catch (\Exception $e) { - throw new UnexpectedValueException( - "Failed to unseal session: " . $e->getMessage() - ); - } - } - - /** - * Derives an encryption key from password using HKDF. - * - * @param string $password Password to derive key from - * - * @return EncryptionKey Encryption key for Halite - * @throws \WorkOS\Exception\UnexpectedValueException - */ - private function deriveKey(string $password): EncryptionKey - { - try { - // Use HKDF to derive a 32-byte key from the password - // This ensures the password is properly formatted for Halite - $keyMaterial = hash_hkdf('sha256', $password, 32); - - return new EncryptionKey(new HiddenString($keyMaterial)); - } catch (\Exception $e) { - throw new UnexpectedValueException( - "Failed to derive encryption key: " . $e->getMessage() - ); - } - } -} diff --git a/lib/Session/SessionEncryptionInterface.php b/lib/Session/SessionEncryptionInterface.php deleted file mode 100644 index 6c08a780..00000000 --- a/lib/Session/SessionEncryptionInterface.php +++ /dev/null @@ -1,34 +0,0 @@ - self::VERSION, - 'd' => $data, - 'e' => $expiry, - ]; - - $payloadJson = json_encode($payload); - $signature = hash_hmac(self::ALGORITHM, $payloadJson, $password, true); - - $sealed = [ - 'p' => base64_encode($payloadJson), - 's' => base64_encode($signature), - ]; - - return base64_encode(json_encode($sealed)); - } - - /** - * Unseal session data by verifying HMAC signature. - * - * @param string $sealed Signed session string - * @param string $password HMAC key - * @return array Unsealed session data - * @throws UnexpectedValueException If signature invalid or expired - */ - public function unseal(string $sealed, string $password): array - { - $decoded = json_decode(base64_decode($sealed), true); - if (!$decoded || !isset($decoded['p']) || !isset($decoded['s'])) { - throw new UnexpectedValueException('Invalid signed session format'); - } - - $payloadJson = base64_decode($decoded['p']); - $providedSignature = base64_decode($decoded['s']); - $expectedSignature = hash_hmac(self::ALGORITHM, $payloadJson, $password, true); - - // Constant-time comparison to prevent timing attacks - if (!hash_equals($expectedSignature, $providedSignature)) { - throw new UnexpectedValueException('Invalid session signature'); - } - - $payload = json_decode($payloadJson, true); - if (!$payload || !isset($payload['v']) || !isset($payload['d']) || !isset($payload['e'])) { - throw new UnexpectedValueException('Invalid payload structure'); - } - - // Version check for future compatibility - if ($payload['v'] !== self::VERSION) { - throw new UnexpectedValueException('Unsupported session version'); - } - - // TTL check - if ($payload['e'] < time()) { - throw new UnexpectedValueException('Session expired'); - } - - return $payload['d']; - } -} diff --git a/lib/SessionManager.php b/lib/SessionManager.php new file mode 100644 index 00000000..9bdde3fe --- /dev/null +++ b/lib/SessionManager.php @@ -0,0 +1,345 @@ + $accessToken, + 'refresh_token' => $refreshToken, + ]; + if ($user !== null) { + $sessionData['user'] = $user; + } + if ($impersonator !== null) { + $sessionData['impersonator'] = $impersonator; + } + + return self::sealData($sessionData, $cookiePassword); + } + + // -- H04: Session cookie object -- + + /** + * Authenticate a sealed session cookie by unsealing and validating the JWT. + * + * Returns an associative array with 'authenticated' => true and session claims + * on success, or 'authenticated' => false and a 'reason' on failure. + * + * @param string $sessionData The sealed session cookie value. + * @param string $cookiePassword The encryption key. + * @param string $clientId The WorkOS client ID (for JWKS URL). + * @param string $baseUrl The WorkOS API base URL. Defaults to 'https://api.workos.com/'. + * @return array Authentication result. + */ + public function authenticate( + string $sessionData, + string $cookiePassword, + string $clientId, + string $baseUrl = 'https://api.workos.com/', + ): array { + if (empty($sessionData)) { + return [ + 'authenticated' => false, + 'reason' => 'no_session_cookie_provided', + ]; + } + + try { + $session = self::unsealData($sessionData, $cookiePassword); + } catch (\Exception $e) { + return [ + 'authenticated' => false, + 'reason' => 'invalid_session_cookie', + ]; + } + + if (empty($session['access_token'])) { + return [ + 'authenticated' => false, + 'reason' => 'invalid_session_cookie', + ]; + } + + try { + $decoded = self::decodeAccessToken($session['access_token'], $clientId, $baseUrl); + } catch (\Exception $e) { + return [ + 'authenticated' => false, + 'reason' => 'invalid_jwt', + ]; + } + + return [ + 'authenticated' => true, + 'session_id' => $decoded['sid'], + 'organization_id' => $decoded['org_id'] ?? null, + 'role' => $decoded['role'] ?? null, + 'roles' => $decoded['roles'] ?? null, + 'permissions' => $decoded['permissions'] ?? null, + 'entitlements' => $decoded['entitlements'] ?? null, + 'user' => $session['user'] ?? null, + 'impersonator' => $session['impersonator'] ?? null, + 'feature_flags' => $decoded['feature_flags'] ?? null, + ]; + } + + // -- H05: Session cookie inline convenience methods -- + + /** + * Refresh a sealed session by exchanging the refresh token. + * + * @param string $sessionData The sealed session cookie value. + * @param string $cookiePassword The encryption key. + * @param string $clientId The WorkOS client ID. + * @param string|null $organizationId Optional organization to scope the refresh to. + * @return array Refresh result with 'authenticated', 'sealed_session', and claims. + */ + public function refresh( + string $sessionData, + string $cookiePassword, + string $clientId, + ?string $organizationId = null, + ): array { + try { + $session = self::unsealData($sessionData, $cookiePassword); + } catch (\Exception $e) { + return [ + 'authenticated' => false, + 'reason' => 'invalid_session_cookie', + ]; + } + + if (empty($session['refresh_token']) || empty($session['user'])) { + return [ + 'authenticated' => false, + 'reason' => 'invalid_session_cookie', + ]; + } + + try { + $body = [ + 'grant_type' => 'refresh_token', + 'client_id' => $clientId, + 'client_secret' => $this->client->requireApiKey(), + 'refresh_token' => $session['refresh_token'], + 'session' => [ + 'seal_session' => true, + 'cookie_password' => $cookiePassword, + ], + ]; + if ($organizationId !== null) { + $body['organization_id'] = $organizationId; + } + + $authResponse = $this->client->request( + method: 'POST', + path: 'user_management/authenticate', + body: $body, + ); + + return [ + 'authenticated' => true, + 'sealed_session' => $authResponse['sealed_session'], + 'session_id' => $authResponse['sid'] ?? null, + 'user' => $authResponse['user'] ?? null, + 'impersonator' => $authResponse['impersonator'] ?? null, + ]; + } catch (\Exception $e) { + return [ + 'authenticated' => false, + 'reason' => $e->getMessage(), + ]; + } + } + + /** + * Get the logout URL for a session. + * + * @param string $sessionData The sealed session cookie value. + * @param string $cookiePassword The encryption key. + * @param string $clientId The WorkOS client ID. + * @param string|null $returnTo Optional URL to redirect to after logout. + * @param string $baseUrl The WorkOS API base URL. + * @return string The logout URL. + * @throws \InvalidArgumentException If the session cannot be authenticated. + */ + public function getLogoutUrl( + string $sessionData, + string $cookiePassword, + string $clientId, + ?string $returnTo = null, + string $baseUrl = 'https://api.workos.com/', + ): string { + $authResult = $this->authenticate($sessionData, $cookiePassword, $clientId, $baseUrl); + + if (!$authResult['authenticated']) { + throw new \InvalidArgumentException( + "Failed to extract session ID for logout URL: {$authResult['reason']}" + ); + } + + $query = ['session_id' => $authResult['session_id']]; + if ($returnTo !== null) { + $query['return_to'] = $returnTo; + } + + return rtrim($baseUrl, '/') . '/user_management/sessions/logout?' . http_build_query($query); + } + + // -- H13: JWKS helper -- + + /** + * Build the JWKS URL for the given client ID. + * + * @param string $clientId The WorkOS client ID. + * @param string $baseUrl The WorkOS API base URL. + * @return string The JWKS URL. + */ + public static function getJwksUrl( + string $clientId, + string $baseUrl = 'https://api.workos.com/', + ): string { + return rtrim($baseUrl, '/') . "/sso/jwks/{$clientId}"; + } + + /** + * Fetch the JWKS keys for the given client ID. + * + * @param string $clientId The WorkOS client ID. + * @return array The JWKS response. + */ + public function fetchJwks(string $clientId): array + { + return $this->client->request( + method: 'GET', + path: "sso/jwks/{$clientId}", + ); + } + + /** + * Decode and validate an access token JWT. + * + * This is a basic JWT decode. For production use, fetch JWKS and validate + * the signature properly. This helper decodes without signature verification + * for extracting claims when the token has already been validated upstream. + * + * @param string $accessToken The JWT access token. + * @param string $clientId The WorkOS client ID (unused in basic decode). + * @param string $baseUrl The WorkOS API base URL (unused in basic decode). + * @return array The decoded JWT claims. + * @throws \InvalidArgumentException If the token cannot be decoded. + */ + private static function decodeAccessToken( + string $accessToken, + string $clientId, + string $baseUrl, + ): array { + $parts = explode('.', $accessToken); + if (count($parts) !== 3) { + throw new \InvalidArgumentException('Invalid JWT format'); + } + + $payload = base64_decode(strtr($parts[1], '-_', '+/'), true); + if ($payload === false) { + throw new \InvalidArgumentException('Invalid JWT payload encoding'); + } + + $decoded = json_decode($payload, true); + if ($decoded === null) { + throw new \InvalidArgumentException('Invalid JWT payload JSON'); + } + + // Check expiration + if (isset($decoded['exp']) && $decoded['exp'] < time()) { + throw new \InvalidArgumentException('JWT has expired'); + } + + return $decoded; + } +} diff --git a/lib/UserManagement.php b/lib/UserManagement.php deleted file mode 100644 index 581650ed..00000000 --- a/lib/UserManagement.php +++ /dev/null @@ -1,1486 +0,0 @@ -sessionEncryptor = $encryptor; - } - - /** - * Set the session encryptor. - * - * @param Session\SessionEncryptionInterface $encryptor - * @return void - */ - public function setSessionEncryptor(Session\SessionEncryptionInterface $encryptor): void - { - $this->sessionEncryptor = $encryptor; - } - - /** - * Get the session encryptor, defaulting to Halite. - * - * @return Session\SessionEncryptionInterface - */ - private function getSessionEncryptor(): Session\SessionEncryptionInterface - { - if ($this->sessionEncryptor === null) { - $this->sessionEncryptor = new Session\HaliteSessionEncryption(); - } - return $this->sessionEncryptor; - } - - /** - * Create User. - * - * @param string $email The email address of the user. - * @param string|null $password The password of the user. - * @param string|null $firstName The first name of the user. - * @param string|null $lastName The last name of the user. - * @param bool|null $emailVerified A boolean declaring if the user's email has been verified. - * @param string|null $passwordHash The hashed password to set for the user. - * @param string|null $passwordHashType The algorithm originally used to hash the password. Valid values are `bcrypt`, `ssha`, and `firebase-scrypt`. - * @param string|null $externalId The user's external ID. - * @param array $metadata The user's metadata. - * @return Resource\User - * - * @throws Exception\WorkOSException - */ - public function createUser( - $email, - ?string $password = null, - ?string $firstName = null, - ?string $lastName = null, - ?bool $emailVerified = null, - ?string $passwordHash = null, - ?string $passwordHashType = null, - ?string $externalId = null, - ?array $metadata = null - ) { - $path = 'user_management/users'; - $params = [ - 'email' => $email, - 'password' => $password, - 'first_name' => $firstName, - 'last_name' => $lastName, - 'email_verified' => $emailVerified, - 'password_hash' => $passwordHash, - 'password_hash_type' => $passwordHashType, - 'external_id' => $externalId, - 'metadata' => $metadata, - ]; - - $response = Client::request(Client::METHOD_POST, $path, null, $params, true); - - return Resource\User::constructFromResponse($response); - } - - /** - * Get a User. - * - * @param string $userId user ID - * @return Resource\User - * - * @throws Exception\WorkOSException - */ - public function getUser($userId) - { - $path = "user_management/users/{$userId}"; - - $response = Client::request(Client::METHOD_GET, $path, null, null, true); - - return Resource\User::constructFromResponse($response); - } - - /** - * Get a User by external ID. - * - * @param string $externalId The external ID of the user. - * @return Resource\User - * - * @throws Exception\WorkOSException - */ - public function getUserByExternalId($externalId) - { - $path = "user_management/users/external_id/{$externalId}"; - - $response = Client::request(Client::METHOD_GET, $path, null, null, true); - - return Resource\User::constructFromResponse($response); - } - - /** - * Update a User - * - * @param string $userId The unique ID of the user. - * @param string|null $firstName The first name of the user. - * @param string|null $lastName The last name of the user. - * @param bool|null $emailVerified A boolean declaring if the user's email has been verified. - * @param string|null $password The password to set for the user. - * @param string|null $passwordHash The hashed password to set for the user. - * @param string|null $passwordHashType The algorithm originally used to hash the password. Valid values are `bcrypt`, `ssha`, and `firebase-scrypt`. - * @param string|null $externalId The user's external ID. - * @param array|null $metadata The user's metadata. - * @param string|null $email The email address of the user. - * @return Resource\User - * - * @throws Exception\WorkOSException - */ - public function updateUser( - $userId, - ?string $firstName = null, - ?string $lastName = null, - ?bool $emailVerified = null, - ?string $password = null, - ?string $passwordHash = null, - ?string $passwordHashType = null, - ?string $externalId = null, - ?array $metadata = null, - ?string $email = null - ) { - $path = "user_management/users/{$userId}"; - - $params = [ - 'first_name' => $firstName, - 'last_name' => $lastName, - 'email_verified' => $emailVerified, - 'password' => $password, - 'password_hash' => $passwordHash, - 'password_hash_type' => $passwordHashType, - 'external_id' => $externalId, - 'metadata' => $metadata, - 'email' => $email, - ]; - - $response = Client::request(Client::METHOD_PUT, $path, null, $params, true); - - return Resource\User::constructFromResponse($response); - } - - /** - * List Users. - * - * @param null|string $organizationId Organization users are a member of - * @param int $limit Maximum number of records to return - * @param null|string $before User ID to look before - * @param null|string $after User ID to look after - * @param Resource\Order $order The Order in which to paginate records - * @return Resource\PaginatedResource A paginated resource containing before/after cursors and users array. - * Supports: [$before, $after, $users] = $result, ["users" => $users] = $result, $result->users - * - * @throws Exception\WorkOSException - */ - public function listUsers( - ?string $email = null, - ?string $organizationId = null, - $limit = self::DEFAULT_PAGE_SIZE, - ?string $before = null, - ?string $after = null, - ?string $order = null - ) { - $path = 'user_management/users'; - - $params = [ - 'email' => $email, - 'organization_id' => $organizationId, - 'limit' => $limit, - 'before' => $before, - 'after' => $after, - 'order' => $order, - ]; - - $response = Client::request( - Client::METHOD_GET, - $path, - null, - $params, - true - ); - - return Resource\PaginatedResource::constructFromResponse($response, Resource\User::class, 'users'); - } - - /** - * Delete a user. - * - * @param string $userId Unique ID of a user - * @return Resource\Response - * - * @throws Exception\WorkOSException - */ - public function deleteUser($userId) - { - $path = "user_management/users/{$userId}"; - - $response = Client::request(Client::METHOD_DELETE, $path, null, null, true); - - return $response; - } - - /** - * Add a User to an Organization. - * - * @param string $userId User ID - * @param string $organizationId Organization ID - * @param string|null $roleSlug Role Slug - * @param array|null $roleSlugs Role Slugs - * @return Resource\OrganizationMembership - * - * @throws Exception\WorkOSException - */ - public function createOrganizationMembership($userId, $organizationId, ?string $roleSlug = null, ?array $roleSlugs = null) - { - $path = 'user_management/organization_memberships'; - - $params = [ - 'organization_id' => $organizationId, - 'user_id' => $userId, - ]; - - if (! is_null($roleSlug)) { - $params['role_slug'] = $roleSlug; - } - - if (! is_null($roleSlugs)) { - $params['role_slugs'] = $roleSlugs; - } - - $response = Client::request( - Client::METHOD_POST, - $path, - null, - $params, - true - ); - - return Resource\OrganizationMembership::constructFromResponse($response); - } - - /** - * Get an Organization Membership. - * - * @param string $organizationMembershipId Organization Membership ID - * @return Resource\OrganizationMembership - * - * @throws Exception\WorkOSException - */ - public function getOrganizationMembership($organizationMembershipId) - { - $path = "user_management/organization_memberships/{$organizationMembershipId}"; - - $response = Client::request( - Client::METHOD_GET, - $path, - null, - null, - true - ); - - return Resource\OrganizationMembership::constructFromResponse($response); - } - - /** - * Remove a user from an organization. - * - * @param string $organizationMembershipId Organization Membership ID - * @return Resource\Response - * - * @throws Exception\WorkOSException - */ - public function deleteOrganizationMembership($organizationMembershipId) - { - $path = "user_management/organization_memberships/{$organizationMembershipId}"; - - $response = Client::request( - Client::METHOD_DELETE, - $path, - null, - null, - true - ); - - return $response; - } - - /** - * Update a User organization membership. - * - * @param string $organizationMembershipId Organization Membership ID - * @param string|null $role_slug The unique slug of the role to grant to this membership. - * @param array|null $role_slugs The unique slugs of the roles to grant to this membership. - * @return Resource\OrganizationMembership - * - * @throws Exception\WorkOSException - */ - public function updateOrganizationMembership($organizationMembershipId, ?string $roleSlug = null, ?array $roleSlugs = null) - { - $path = "user_management/organization_memberships/{$organizationMembershipId}"; - - $params = []; - - if (! is_null($roleSlug)) { - $params['role_slug'] = $roleSlug; - } - - if (! is_null($roleSlugs)) { - $params['role_slugs'] = $roleSlugs; - } - - $response = Client::request( - Client::METHOD_PUT, - $path, - null, - $params, - true - ); - - return Resource\OrganizationMembership::constructFromResponse($response); - } - - /** - * List organization memberships. - * - * @param string|null $userId User ID - * @param string|null $organizationId Organization ID - * @param array|null $statuses Organization Membership statuses to filter - * @param int $limit Maximum number of records to return - * @param string|null $before Organization Membership ID to look before - * @param string|null $after Organization Membership ID to look after - * @param Resource\Order $order The Order in which to paginate records - * @return Resource\PaginatedResource A paginated resource containing before/after cursors and organization_memberships array. - * Supports: [$before, $after, $memberships] = $result, ["organization_memberships" => $m] = $result, $result->organization_memberships - * - * @throws Exception\WorkOSException - */ - public function listOrganizationMemberships( - ?string $userId = null, - ?string $organizationId = null, - ?array $statuses = null, - $limit = self::DEFAULT_PAGE_SIZE, - ?string $before = null, - ?string $after = null, - ?string $order = null - ) { - $path = 'user_management/organization_memberships'; - - if (isset($statuses)) { - if (! is_array($statuses)) { - $msg = 'Invalid argument: statuses must be an array or null.'; - throw new Exception\UnexpectedValueException($msg); - } - - $statuses = implode(',', $statuses); - } - - $params = [ - 'organization_id' => $organizationId, - 'user_id' => $userId, - 'statuses' => $statuses, - 'limit' => $limit, - 'before' => $before, - 'after' => $after, - 'order' => $order, - ]; - - $response = Client::request( - Client::METHOD_GET, - $path, - null, - $params, - true - ); - - return Resource\PaginatedResource::constructFromResponse($response, Resource\OrganizationMembership::class, 'organization_memberships'); - } - - /** - * Deactivate an Organization Membership. - * - * @param string $organizationMembershipId Organization Membership ID - * @return Resource\OrganizationMembership - * - * @throws Exception\WorkOSException - */ - public function deactivateOrganizationMembership($organizationMembershipId) - { - $path = "user_management/organization_memberships/{$organizationMembershipId}/deactivate"; - - $response = Client::request( - Client::METHOD_PUT, - $path, - null, - null, - true - ); - - return Resource\OrganizationMembership::constructFromResponse($response); - } - - /** - * Reactivate an Organization Membership. - * - * @param string $organizationMembershipId Organization Membership ID - * @return Resource\OrganizationMembership - * - * @throws Exception\WorkOSException - */ - public function reactivateOrganizationMembership($organizationMembershipId) - { - $path = "user_management/organization_memberships/{$organizationMembershipId}/reactivate"; - - $response = Client::request( - Client::METHOD_PUT, - $path, - null, - null, - true - ); - - return Resource\OrganizationMembership::constructFromResponse($response); - } - - /** - * Sends an Invitation - * - * @param string $email The email address of the invitee - * @param string|null $organizationId Organization ID - * @param int|null $expiresInDays expiration delay in days - * @param string|null $inviterUserId User ID of the inviter - * @param string|null $roleSlug Slug of the role to assign to the invitee User - * @return Resource\Invitation - * - * @throws Exception\WorkOSException - */ - public function sendInvitation( - $email, - ?string $organizationId = null, - ?int $expiresInDays = null, - ?string $inviterUserId = null, - ?string $roleSlug = null - ) { - $path = 'user_management/invitations'; - - $params = [ - 'email' => $email, - 'organization_id' => $organizationId, - 'expires_in_days' => $expiresInDays, - 'inviter_user_id' => $inviterUserId, - 'role_slug' => $roleSlug, - ]; - - $response = Client::request( - Client::METHOD_POST, - $path, - null, - $params, - true - ); - - return Resource\Invitation::constructFromResponse($response); - } - - /** - * Get an Invitation - * - * @param string $invitationId ID of the Invitation - * @return Resource\Invitation - * - * @throws Exception\WorkOSException - */ - public function getInvitation($invitationId) - { - $path = "user_management/invitations/{$invitationId}"; - - $response = Client::request( - Client::METHOD_GET, - $path, - null, - null, - true - ); - - return Resource\Invitation::constructFromResponse($response); - } - - /** - * Find an Invitation by Token - * - * @param string $invitationToken The token of the Invitation - * @return Resource\Invitation - * - * @throws Exception\WorkOSException - */ - public function findInvitationByToken($invitationToken) - { - $path = "user_management/invitations/by_token/{$invitationToken}"; - - $response = Client::request( - Client::METHOD_GET, - $path, - null, - null, - true - ); - - return Resource\Invitation::constructFromResponse($response); - } - - /** - * List Invitations - * - * @param string|null $email Email of the invitee - * @param string|null $organizationId Organization ID - * @param int $limit Maximum number of records to return - * @param string|null $before Organization Membership ID to look before - * @param string|null $after Organization Membership ID to look after - * @param Resource\Order $order The Order in which to paginate records - * @return Resource\PaginatedResource A paginated resource containing before/after cursors and invitations array. - * Supports: [$before, $after, $invitations] = $result, ["invitations" => $invitations] = $result, $result->invitations - * - * @throws Exception\WorkOSException - */ - public function listInvitations( - ?string $email = null, - ?string $organizationId = null, - $limit = self::DEFAULT_PAGE_SIZE, - ?string $before = null, - ?string $after = null, - ?string $order = null - ) { - $path = 'user_management/invitations'; - - $params = [ - 'email' => $email, - 'organization_id' => $organizationId, - 'limit' => $limit, - 'before' => $before, - 'after' => $after, - 'order' => $order, - ]; - - $response = Client::request( - Client::METHOD_GET, - $path, - null, - $params, - true - ); - - return Resource\PaginatedResource::constructFromResponse($response, Resource\Invitation::class, 'invitations'); - } - - /** - * Revoke an Invitation - * - * @param string $invitationId ID of the Invitation - * @return Resource\Invitation - * - * @throws Exception\WorkOSException - */ - public function revokeInvitation($invitationId) - { - $path = "user_management/invitations/{$invitationId}/revoke"; - - $response = Client::request( - Client::METHOD_POST, - $path, - null, - null, - true - ); - - return Resource\Invitation::constructFromResponse($response); - } - - /** - * Resend an Invitation - * - * @param string $invitationId ID of the Invitation - * @return Resource\Invitation - * - * @throws Exception\WorkOSException - */ - public function resendInvitation($invitationId) - { - $path = "user_management/invitations/{$invitationId}/resend"; - - $response = Client::request( - Client::METHOD_POST, - $path, - null, - null, - true - ); - - return Resource\Invitation::constructFromResponse($response); - } - - /** - * Accept an Invitation - * - * @param string $invitationId ID of the Invitation - * @return Resource\Invitation - * - * @throws Exception\WorkOSException - */ - public function acceptInvitation($invitationId) - { - $path = "user_management/invitations/{$invitationId}/accept"; - - $response = Client::request( - Client::METHOD_POST, - $path, - null, - null, - true - ); - - return Resource\Invitation::constructFromResponse($response); - } - - /** - * Generates an OAuth 2.0 authorization URL used to initiate the SSO flow with WorkOS. - * - * @param string $redirectUri URI to direct the user to upon successful completion of SSO - * @param null|array $state Associative array containing state that will be returned from WorkOS as a json encoded string - * @param null|string $provider Service provider that handles the identity of the user - * @param null|string $connectionId Unique identifier for a WorkOS Connection - * @param null|string $organizationId Unique identifier for a WorkOS Organization - * @param null|string $domainHint Domain hint that will be passed as a parameter to the IdP login page - * @param null|string $loginHint Username/email hint that will be passed as a parameter to the to IdP login page - * @param null|string $screenHint The page that the user will be redirected to when the provider is authkit - * @param null|array $providerScopes An array of provider-specific scopes - * @return string - * - * @throws Exception\UnexpectedValueException - * @throws Exception\ConfigurationException - */ - public function getAuthorizationUrl( - $redirectUri, - $state = null, - $provider = null, - ?string $connectionId = null, - ?string $organizationId = null, - ?string $domainHint = null, - ?string $loginHint = null, - ?string $screenHint = null, - ?array $providerScopes = null - ) { - $path = 'user_management/authorize'; - - if (! isset($provider) && ! isset($connectionId) && ! isset($organizationId)) { - $msg = 'Either $provider, $connectionId, or $organizationId is required'; - throw new Exception\UnexpectedValueException($msg); - } - - $supportedProviders = [ - self::AUTHORIZATION_PROVIDER_AUTHKIT, - self::AUTHORIZATION_PROVIDER_APPLE_OAUTH, - self::AUTHORIZATION_PROVIDER_GITHUB_OAUTH, - self::AUTHORIZATION_PROVIDER_GOOGLE_OAUTH, - self::AUTHORIZATION_PROVIDER_MICROSOFT_OAUTH, - ]; - - if (isset($provider) && ! \in_array($provider, $supportedProviders)) { - $msg = 'Only '.implode("','", $supportedProviders).' providers are supported'; - throw new Exception\UnexpectedValueException($msg); - } - - $params = [ - 'client_id' => WorkOS::getClientId(), - 'response_type' => 'code', - ]; - - if ($redirectUri) { - $params['redirect_uri'] = $redirectUri; - } - - if ($state !== null && ! empty($state)) { - $params['state'] = \json_encode($state); - } - - if ($provider) { - $params['provider'] = $provider; - } - - if ($connectionId) { - $params['connection_id'] = $connectionId; - } - - if ($organizationId) { - $params['organization_id'] = $organizationId; - } - - if ($domainHint) { - $params['domain_hint'] = $domainHint; - } - - if ($loginHint) { - $params['login_hint'] = $loginHint; - } - - if ($screenHint !== null) { - if ($provider !== self::AUTHORIZATION_PROVIDER_AUTHKIT) { - throw new Exception\UnexpectedValueException("A 'screenHint' can only be provided when the provider is 'authkit'."); - } - $params['screen_hint'] = $screenHint; - } - - if ($providerScopes && is_array($providerScopes)) { - $params['provider_scopes'] = implode(',', $providerScopes); - } - - return Client::generateUrl($path, $params); - } - - /** - * Authenticate a User with Password - * - * @param string $clientId This value can be obtained from the API Keys page in the WorkOS dashboard. - * @param string $email The email address of the user. - * @param string $password The password of the user. - * @param string|null $ipAddress The IP address of the request from the user who is attempting to authenticate. - * @param string|null $userAgent The user agent of the request from the user who is attempting to authenticate. - * @return Resource\AuthenticationResponse - * - * @throws Exception\WorkOSException - */ - public function authenticateWithPassword($clientId, $email, $password, ?string $ipAddress = null, ?string $userAgent = null) - { - $path = 'user_management/authenticate'; - $params = [ - 'client_id' => $clientId, - 'email' => $email, - 'password' => $password, - 'ip_address' => $ipAddress, - 'user_agent' => $userAgent, - 'grant_type' => 'password', - 'client_secret' => WorkOS::getApiKey(), - ]; - - $response = Client::request(Client::METHOD_POST, $path, null, $params, true); - - return Resource\AuthenticationResponse::constructFromResponse($response); - } - - /** - * Authenticate a User with Selected Organization - * - * @param string $clientId This value can be obtained from the API Keys page in the WorkOS dashboard. - * @param string $pendingAuthenticationToken Token returned from a failed authentication attempt due to organization selection being required. - * @param string $organizationId The Organization ID the user selected. - * @param string|null $ipAddress The IP address of the request from the user who is attempting to authenticate. - * @param string|null $userAgent The user agent of the request from the user who is attempting to authenticate. - * @return Resource\AuthenticationResponse - * - * @throws Exception\WorkOSException - */ - public function authenticateWithSelectedOrganization( - $clientId, - $pendingAuthenticationToken, - $organizationId, - ?string $ipAddress = null, - ?string $userAgent = null - ) { - $path = 'user_management/authenticate'; - $params = [ - 'client_id' => $clientId, - 'pending_authentication_token' => $pendingAuthenticationToken, - 'organization_id' => $organizationId, - 'ip_address' => $ipAddress, - 'user_agent' => $userAgent, - 'grant_type' => 'urn:workos:oauth:grant-type:organization-selection', - 'client_secret' => WorkOS::getApiKey(), - ]; - - $response = Client::request(Client::METHOD_POST, $path, null, $params, true); - - return Resource\AuthenticationResponse::constructFromResponse($response); - } - - /** - * Authenticate an OAuth or SSO User with a Code - * This should be used for "Hosted AuthKit" and "OAuth or SSO" UserAuthentications - * - * @param string $clientId This value can be obtained from the API Keys page in the WorkOS dashboard. - * @param string $code The authorization value which was passed back as a query parameter in the callback to the Redirect URI. - * @param string|null $ipAddress The IP address of the request from the user who is attempting to authenticate. - * @param string|null $userAgent The user agent of the request from the user who is attempting to authenticate. - * @return Resource\AuthenticationResponse - * - * @throws Exception\WorkOSException - */ - public function authenticateWithCode($clientId, $code, ?string $ipAddress = null, ?string $userAgent = null) - { - $path = 'user_management/authenticate'; - $params = [ - 'client_id' => $clientId, - 'code' => $code, - 'ip_address' => $ipAddress, - 'user_agent' => $userAgent, - 'grant_type' => 'authorization_code', - 'client_secret' => WorkOS::getApiKey(), - ]; - - $response = Client::request(Client::METHOD_POST, $path, null, $params, true); - - return Resource\AuthenticationResponse::constructFromResponse($response); - } - - /** - * Authenticates a user with an unverified email and verifies their email address. - * - * @param string $clientId This value can be obtained from the API Keys page in the WorkOS dashboard. - * @param string $code The authorization value which was passed back as a query parameter in the callback to the Redirect URI. - * @param string $pendingAuthenticationToken Token returned from a failed authentication attempt due to organization selection being required. - * @param string|null $ipAddress The IP address of the request from the user who is attempting to authenticate. - * @param string|null $userAgent The user agent of the request from the user who is attempting to authenticate. - * @return Resource\AuthenticationResponse - * - * @throws Exception\WorkOSException - */ - public function authenticateWithEmailVerification($clientId, $code, $pendingAuthenticationToken, ?string $ipAddress = null, ?string $userAgent = null) - { - $path = 'user_management/authenticate'; - $params = [ - 'client_id' => $clientId, - 'code' => $code, - 'pending_authentication_token' => $pendingAuthenticationToken, - 'ip_address' => $ipAddress, - 'user_agent' => $userAgent, - 'grant_type' => 'urn:workos:oauth:grant-type:email-verification:code', - 'client_secret' => WorkOS::getApiKey(), - ]; - - $response = Client::request(Client::METHOD_POST, $path, null, $params, true); - - return Resource\AuthenticationResponse::constructFromResponse($response); - } - - /** - * Authenticate with Magic Auth - * - * @param string $clientId This value can be obtained from the API Keys page in the WorkOS dashboard. - * @param string $code The authorization value which was passed back as a query parameter in the callback to the Redirect URI. - * @param string $userId The unique ID of the user. - * @param string|null $ipAddress The IP address of the request from the user who is attempting to authenticate. - * @param string|null $userAgent The user agent of the request from the user who is attempting to authenticate. - * @return Resource\AuthenticationResponse - * - * @throws Exception\WorkOSException - */ - public function authenticateWithMagicAuth( - $clientId, - $code, - $userId, - ?string $ipAddress = null, - ?string $userAgent = null - ) { - $path = 'user_management/authenticate'; - $params = [ - 'client_id' => $clientId, - 'code' => $code, - 'user_id' => $userId, - 'ip_address' => $ipAddress, - 'user_agent' => $userAgent, - 'grant_type' => 'urn:workos:oauth:grant-type:magic-auth:code', - 'client_secret' => WorkOS::getApiKey(), - ]; - - $response = Client::request(Client::METHOD_POST, $path, null, $params, true); - - return Resource\AuthenticationResponse::constructFromResponse($response); - } - - /** - * Authenticate with Refresh Token - * - * @param string $clientId This value can be obtained from the API Keys page in the WorkOS dashboard. - * @param string $refreshToken The refresh token used to obtain a new access token - * @param string|null $ipAddress The IP address of the request from the user who is attempting to authenticate. - * @param string|null $userAgent The user agent of the request from the user who is attempting to authenticate. - * @param string|null $organizationId The user agent of the request from the user who is attempting to authenticate. - * @return Resource\AuthenticationResponse - * - * @throws Exception\WorkOSException - */ - public function authenticateWithRefreshToken( - $clientId, - $refreshToken, - ?string $ipAddress = null, - ?string $userAgent = null, - ?string $organizationId = null - ) { - $path = 'user_management/authenticate'; - $params = [ - 'client_id' => $clientId, - 'refresh_token' => $refreshToken, - 'organization_id' => $organizationId, - 'ip_address' => $ipAddress, - 'user_agent' => $userAgent, - 'grant_type' => 'refresh_token', - 'client_secret' => WorkOS::getApiKey(), - ]; - - $response = Client::request(Client::METHOD_POST, $path, null, $params, true); - - return Resource\AuthenticationResponse::constructFromResponse($response); - } - - /** - * Authenticate with TOTP - * - * @param string $clientId This value can be obtained from the API Keys page in the WorkOS dashboard. - * @param string $pendingAuthenticationToken - * @param string $authenticationChallengeId - * @param string $code - * @param string|null $ipAddress The IP address of the request from the user who is attempting to authenticate. - * @param string|null $userAgent The user agent of the request from the user who is attempting to authenticate. - * @return Resource\AuthenticationResponse - * - * @throws Exception\WorkOSException - */ - public function authenticateWithTotp( - $clientId, - $pendingAuthenticationToken, - $authenticationChallengeId, - $code, - ?string $ipAddress = null, - ?string $userAgent = null - ) { - $path = 'user_management/authenticate'; - $params = [ - 'client_id' => $clientId, - 'pending_authentication_token' => $pendingAuthenticationToken, - 'authentication_challenge_id' => $authenticationChallengeId, - 'code' => $code, - 'ip_address' => $ipAddress, - 'user_agent' => $userAgent, - 'grant_type' => 'urn:workos:oauth:grant-type:mfa-totp', - 'client_secret' => WorkOS::getApiKey(), - ]; - - $response = Client::request(Client::METHOD_POST, $path, null, $params, true); - - return Resource\AuthenticationResponse::constructFromResponse($response); - } - - /** - * Enroll An Authentication Factor. - * - * @param string $userId The unique ID of the user. - * @param string $type The type of MFA factor used to authenticate. - * @param string|null $totpIssuer Your application or company name, this helps users distinguish between factors in authenticator apps. - * @param string|null $totpUser Used as the account name in authenticator apps. - * @return Resource\AuthenticationFactorAndChallengeTotp - * - * @throws Exception\WorkOSException - */ - public function enrollAuthFactor($userId, $type, ?string $totpIssuer = null, ?string $totpUser = null) - { - $path = "user_management/users/{$userId}/auth_factors"; - - $params = [ - 'type' => $type, - 'totp_user' => $totpUser, - 'totp_issuer' => $totpIssuer, - ]; - - $response = Client::request(Client::METHOD_POST, $path, null, $params, true); - - return Resource\AuthenticationFactorAndChallengeTotp::constructFromResponse($response); - } - - /** - * List a User's Authentication Factors. - * - * @param string $userId The unique ID of the user. - * @return Resource\UserAuthenticationFactorTotp[] $authFactors A list of user's authentication factors - * - * @throws Exception\WorkOSException - */ - public function listAuthFactors($userId) - { - $path = "user_management/users/{$userId}/auth_factors"; - - $response = Client::request(Client::METHOD_GET, $path, null, null, true); - - $authFactors = []; - - foreach ($response['data'] as $responseData) { - \array_push($authFactors, Resource\UserAuthenticationFactorTotp::constructFromResponse($responseData)); - } - - return $authFactors; - } - - /** - * Get an email verification object - * - * @param string $emailVerificationId ID of the email verification object - * @return Resource\EmailVerification - * - * @throws Exception\WorkOSException - */ - public function getEmailVerification($emailVerificationId) - { - $path = "user_management/email_verification/{$emailVerificationId}"; - - $response = Client::request( - Client::METHOD_GET, - $path, - null, - null, - true - ); - - return Resource\EmailVerification::constructFromResponse($response); - } - - /** - * Create Email Verification Challenge. - * - * @param string $userId The unique ID of the User whose email address will be verified. - * @return Resource\UserResponse - * - * @throws Exception\WorkOSException - */ - public function sendVerificationEmail($userId) - { - $path = "user_management/users/{$userId}/email_verification/send"; - - $response = Client::request(Client::METHOD_POST, $path, null, null, true); - - return Resource\UserResponse::constructFromResponse($response); - } - - /** - * Complete Email Verification. - * - * @param string $userId The unique ID of the user. - * @param string $code The one-time code emailed to the user. - * @return Resource\UserResponse - * - * @throws Exception\WorkOSException - */ - public function verifyEmail($userId, $code) - { - $path = "user_management/users/{$userId}/email_verification/confirm"; - - $params = [ - 'code' => $code, - ]; - - $response = Client::request(Client::METHOD_POST, $path, null, $params, true); - - return Resource\UserResponse::constructFromResponse($response); - } - - /** - * Get a password reset object - * - * @param string $passwordResetId ID of the password reset object - * @return Resource\PasswordReset - * - * @throws Exception\WorkOSException - */ - public function getPasswordReset($passwordResetId) - { - $path = "user_management/password_reset/{$passwordResetId}"; - - $response = Client::request( - Client::METHOD_GET, - $path, - null, - null, - true - ); - - return Resource\PasswordReset::constructFromResponse($response); - } - - /** - * Creates a password reset token - * - * @param string $email The email address of the user - * @return Resource\PasswordReset - * - * @throws Exception\WorkOSException - */ - public function createPasswordReset( - $email - ) { - $path = 'user_management/password_reset'; - - $params = [ - 'email' => $email, - ]; - - $response = Client::request( - Client::METHOD_POST, - $path, - null, - $params, - true - ); - - return Resource\PasswordReset::constructFromResponse($response); - } - - /** - * @deprecated 4.9.0 Use `createPasswordReset` instead. This method will be removed in a future major version. - * Create Password Reset Email. - * - * @param string $email The email of the user that wishes to reset their password. - * @param string $passwordResetUrl The URL that will be linked to in the email. - * @return Resource\Response - * - * @throws Exception\WorkOSException - */ - public function sendPasswordResetEmail($email, $passwordResetUrl) - { - $msg = "'sendPasswordResetEmail' is deprecated. Please use 'createPasswordReset' instead. This method will be removed in a future major version."; - - error_log($msg); - - $path = 'user_management/password_reset/send'; - - $params = [ - 'email' => $email, - 'password_reset_url' => $passwordResetUrl, - ]; - - $response = Client::request(Client::METHOD_POST, $path, null, $params, true); - - return $response; - } - - /** - * Complete Password Reset. - * - * @param string $token The reset token emailed to the user. - * @param string $newPassword The new password to be set for the user. - * @return Resource\UserResponse - * - * @throws Exception\WorkOSException - */ - public function resetPassword($token, $newPassword) - { - $path = 'user_management/password_reset/confirm'; - - $params = [ - 'token' => $token, - 'new_password' => $newPassword, - ]; - - $response = Client::request(Client::METHOD_POST, $path, null, $params, true); - - return Resource\UserResponse::constructFromResponse($response); - } - - /** - * Get a Magic Auth object - * - * @param string $magicAuthId ID of the Magic Auth object - * @return Resource\MagicAuth - * - * @throws Exception\WorkOSException - */ - public function getMagicAuth($magicAuthId) - { - $path = "user_management/magic_auth/{$magicAuthId}"; - - $response = Client::request( - Client::METHOD_GET, - $path, - null, - null, - true - ); - - return Resource\MagicAuth::constructFromResponse($response); - } - - /** - * Creates a Magic Auth code - * - * @param string $email The email address of the user - * @param string|null $invitationToken The token of an Invitation, if required. - * @return Resource\MagicAuth - * - * @throws Exception\WorkOSException - */ - public function createMagicAuth( - $email, - ?string $invitationToken = null - ) { - $path = 'user_management/magic_auth'; - - $params = [ - 'email' => $email, - 'invitation_token' => $invitationToken, - ]; - - $response = Client::request( - Client::METHOD_POST, - $path, - null, - $params, - true - ); - - return Resource\MagicAuth::constructFromResponse($response); - } - - /** - * @deprecated 4.6.0 Use `createMagicAuth` instead. This method will be removed in a future major version. - * Creates a one-time Magic Auth code and emails it to the user. - * - * @param string $email The email address the one-time code will be sent to. - * @return Resource\Response - * - * @throws Exception\WorkOSException - */ - public function sendMagicAuthCode($email) - { - $path = 'user_management/magic_auth/send'; - - $params = [ - 'email' => $email, - ]; - - $msg = "'sendMagicAuthCode' is deprecated. Please use 'createMagicAuth' instead. This method will be removed in a future major version."; - - error_log($msg); - - $response = Client::request( - Client::METHOD_POST, - $path, - null, - $params, - true - ); - - return $response; - } - - /** - * Returns the public key host that is used for verifying access tokens. - * - * @param string $clientId This value can be obtained from the API Keys page in the WorkOS dashboard. - * @return string - * - * @throws Exception\UnexpectedValueException - */ - public function getJwksUrl(string $clientId) - { - if (! isset($clientId) || empty($clientId)) { - throw new Exception\UnexpectedValueException('clientId must not be empty'); - } - - $baseUrl = WorkOS::getApiBaseUrl(); - - return "{$baseUrl}sso/jwks/{$clientId}"; - } - - /** - * Returns the logout URL to end a user's session and redirect to your home page. - * - * @param string $sessionId The session ID of the user. - * @param string|null $return_to The URL to redirect to after the user logs out. - * @return string - */ - public function getLogoutUrl(string $sessionId, ?string $return_to = null) - { - if (! isset($sessionId) || empty($sessionId)) { - throw new Exception\UnexpectedValueException('sessionId must not be empty'); - } - - $params = ['session_id' => $sessionId]; - if ($return_to) { - $params['return_to'] = $return_to; - } - - return Client::generateUrl('user_management/sessions/logout', $params); - } - - /** - * List sessions for a user. - * - * @param string $userId User ID - * @param array $options Additional options - * - 'limit' (int): Maximum number of records to return (default: 10) - * - 'before' (string|null): Session ID to look before - * - 'after' (string|null): Session ID to look after - * - 'order' (string|null): The order in which to paginate records - * - * @return Resource\PaginatedResource A paginated resource containing before/after cursors and sessions array. - * Supports: [$before, $after, $sessions] = $result, ["sessions" => $sessions] = $result, $result->sessions - * @throws Exception\WorkOSException - */ - public function listSessions(string $userId, array $options = []) - { - $path = "user_management/users/{$userId}/sessions"; - - $params = [ - "limit" => $options['limit'] ?? self::DEFAULT_PAGE_SIZE, - "before" => $options['before'] ?? null, - "after" => $options['after'] ?? null, - "order" => $options['order'] ?? null - ]; - - $response = Client::request( - Client::METHOD_GET, - $path, - null, - $params, - true - ); - - return Resource\PaginatedResource::constructFromResponse($response, Resource\Session::class, 'sessions'); - } - - /** - * Revoke a session. - * - * @param string $sessionId Session ID - * - * @return Resource\Session The revoked session - * @throws Exception\WorkOSException - */ - public function revokeSession(string $sessionId) - { - $path = "user_management/sessions/revoke"; - - $response = Client::request( - Client::METHOD_POST, - $path, - null, - [ - "session_id" => $sessionId, - ], - true - ); - - return Resource\Session::constructFromResponse($response); - } - - /** - * Authenticate with a sealed session cookie. - * - * @param string $sealedSession Encrypted session cookie data - * @param string $cookiePassword Password to decrypt the session - * - * @return Resource\SessionAuthenticationSuccessResponse|Resource\SessionAuthenticationFailureResponse - * @throws Exception\WorkOSException - */ - public function authenticateWithSessionCookie( - string $sealedSession, - string $cookiePassword - ) { - if (empty($sealedSession)) { - return new Resource\SessionAuthenticationFailureResponse( - Resource\SessionAuthenticationFailureResponse::REASON_NO_SESSION_COOKIE_PROVIDED - ); - } - - // Tight try/catch for unsealing only - try { - $sessionData = $this->getSessionEncryptor()->unseal($sealedSession, $cookiePassword); - } catch (\Exception $e) { - return new Resource\SessionAuthenticationFailureResponse( - Resource\SessionAuthenticationFailureResponse::REASON_ENCRYPTION_ERROR - ); - } - - if (!isset($sessionData['access_token']) || !isset($sessionData['refresh_token'])) { - return new Resource\SessionAuthenticationFailureResponse( - Resource\SessionAuthenticationFailureResponse::REASON_INVALID_SESSION_COOKIE - ); - } - - // Separate try/catch for HTTP request - try { - $path = "user_management/sessions/authenticate"; - $params = [ - "access_token" => $sessionData['access_token'], - "refresh_token" => $sessionData['refresh_token'] - ]; - - $response = Client::request( - Client::METHOD_POST, - $path, - null, - $params, - true - ); - - return Resource\SessionAuthenticationSuccessResponse::constructFromResponse($response); - } catch (Exception\BaseRequestException $e) { - return new Resource\SessionAuthenticationFailureResponse( - Resource\SessionAuthenticationFailureResponse::REASON_HTTP_ERROR - ); - } - } - - /** - * Load a sealed session and return a CookieSession instance. - * - * @param string $sealedSession Encrypted session cookie data - * @param string $cookiePassword Password to decrypt the session - * - * @return CookieSession - */ - public function loadSealedSession(string $sealedSession, string $cookiePassword) - { - return new CookieSession($this, $sealedSession, $cookiePassword); - } - - /** - * Extract and decrypt a session from HTTP cookies. - * - * @param string $cookiePassword Password to decrypt the session - * @param string $cookieName Name of the session cookie (default: 'wos-session') - * - * @return CookieSession|null - */ - public function getSessionFromCookie( - string $cookiePassword, - string $cookieName = 'wos-session' - ) { - if (!isset($_COOKIE[$cookieName])) { - return null; - } - - $sealedSession = $_COOKIE[$cookieName]; - return $this->loadSealedSession($sealedSession, $cookiePassword); - } -} diff --git a/lib/Util/Request.php b/lib/Util/Request.php deleted file mode 100644 index b080d3f7..00000000 --- a/lib/Util/Request.php +++ /dev/null @@ -1,14 +0,0 @@ -client->request( + method: 'GET', + path: "vault/v1/kv/{$objectId}", + ); + } + + /** + * Get a Vault object by name with the value decrypted. + */ + public function readObjectByName(string $name): array + { + return $this->client->request( + method: 'GET', + path: "vault/v1/kv/name/{$name}", + ); + } + + /** + * Get a Vault object's metadata without decrypting the value. + */ + public function getObjectMetadata(string $objectId): array + { + return $this->client->request( + method: 'GET', + path: "vault/v1/kv/{$objectId}/metadata", + ); + } + + /** + * Gets a list of encrypted Vault objects. + */ + public function listObjects( + int $limit = self::DEFAULT_RESPONSE_LIMIT, + ?string $before = null, + ?string $after = null, + ): array { + $query = array_filter([ + 'limit' => $limit, + 'before' => $before, + 'after' => $after, + ], fn ($v) => $v !== null); + + return $this->client->request( + method: 'GET', + path: 'vault/v1/kv', + query: $query, + ); + } + + /** + * Gets a list of versions for a specific Vault object. */ - public function getVaultObject($vaultObjectId) + public function listObjectVersions(string $objectId): array { - $vaultObjectPath = "vault/v1/kv/{$vaultObjectId}"; + return $this->client->request( + method: 'GET', + path: "vault/v1/kv/{$objectId}/versions", + ); + } - $response = Client::request(Client::METHOD_GET, $vaultObjectPath, null, null, true); + /** + * Create a new Vault encrypted object. + */ + public function createObject(string $name, string $value, array $keyContext): array + { + return $this->client->request( + method: 'POST', + path: 'vault/v1/kv', + body: [ + 'name' => $name, + 'value' => $value, + 'key_context' => $keyContext, + ], + ); + } - return Resource\VaultObject::constructFromResponse($response); + /** + * Update an existing Vault object. + */ + public function updateObject( + string $objectId, + string $value, + ?string $versionCheck = null, + ): array { + $body = ['value' => $value]; + if ($versionCheck !== null) { + $body['version_check'] = $versionCheck; + } + + return $this->client->request( + method: 'PUT', + path: "vault/v1/kv/{$objectId}", + body: $body, + ); } /** - * List Vault Objects. + * Permanently delete a Vault encrypted object. + */ + public function deleteObject(string $objectId): void + { + $this->client->request( + method: 'DELETE', + path: "vault/v1/kv/{$objectId}", + ); + } + + // -- Key operations -- + + /** + * Generate a data key for local encryption. + */ + public function createDataKey(array $keyContext): array + { + return $this->client->request( + method: 'POST', + path: 'vault/v1/keys/data-key', + body: ['context' => $keyContext], + ); + } + + /** + * Decrypt encrypted data keys previously generated by createDataKey. + */ + public function decryptDataKey(string $keys): array + { + return $this->client->request( + method: 'POST', + path: 'vault/v1/keys/decrypt', + body: ['keys' => $keys], + ); + } + + // -- Client-side encryption (H18) -- + + /** + * Encrypt data locally using AES-GCM with a data key derived from the context. * - * @param int $limit Maximum number of records to return - * @param null|string $before Vault Object ID to look before - * @param null|string $after Vault Object ID to look after - * @param Resource\Order $order The Order in which to paginate records + * @param string $data The plaintext data to encrypt. + * @param array $keyContext The key context for data key derivation. + * @param string|null $associatedData Additional authenticated data (AAD). (Optional) + * @return string The base64-encoded encrypted payload. + */ + public function encrypt( + string $data, + array $keyContext, + ?string $associatedData = null, + ): string { + $keyPair = $this->createDataKey($keyContext); + + $key = base64_decode($keyPair['data_key']); + $keyBlob = base64_decode($keyPair['encrypted_keys']); + $prefixLenBuffer = self::encodeU32Leb128(strlen($keyBlob)); + $iv = random_bytes(12); + + $result = self::aesGcmEncrypt($data, $key, $iv, $associatedData); + + $combined = $result['iv'] . $result['tag'] . $prefixLenBuffer . $keyBlob . $result['ciphertext']; + return base64_encode($combined); + } + + /** + * Decrypt data that was previously encrypted using the encrypt method. * - * @return Resource\PaginatedResource A paginated resource containing before/after cursors and vault_objects array. - * Supports: [$before, $after, $objects] = $result, ["vault_objects" => $objects] = $result, $result->vault_objects + * @param string $encryptedData The base64-encoded encrypted payload. + * @param string|null $associatedData Additional authenticated data (AAD). (Optional) + * @return string The decrypted plaintext. + */ + public function decrypt( + string $encryptedData, + ?string $associatedData = null, + ): string { + $decoded = self::decodeEncryptedPayload($encryptedData); + $dataKey = $this->decryptDataKey($decoded['keys']); + + $key = base64_decode($dataKey['data_key']); + + return self::aesGcmDecrypt( + $decoded['ciphertext'], + $key, + $decoded['iv'], + $decoded['tag'], + $associatedData, + ); + } + + // -- Crypto helpers -- + + /** + * AES-256-GCM encrypt. * - * @throws Exception\WorkOSException + * @return array{ciphertext: string, iv: string, tag: string} */ - public function listVaultObjects( - $limit = self::DEFAULT_PAGE_SIZE, - $before = null, - $after = null, - $order = null - ) { - $vaultObjectsPath = "vault/v1/kv"; - $params = [ - "limit" => $limit, - "before" => $before, - "after" => $after, - "order" => $order - ]; - - $response = Client::request( - Client::METHOD_GET, - $vaultObjectsPath, - null, - $params, - true + private static function aesGcmEncrypt( + string $plaintext, + string $key, + string $iv, + ?string $aad, + ): array { + $tag = ''; + $ciphertext = openssl_encrypt( + $plaintext, + 'aes-256-gcm', + $key, + OPENSSL_RAW_DATA, + $iv, + $tag, + $aad ?? '', + 16, ); - return Resource\PaginatedResource::constructFromResponse($response, Resource\VaultObject::class, 'vault_objects'); + if ($ciphertext === false) { + throw new \RuntimeException('AES-GCM encryption failed'); + } + + return ['ciphertext' => $ciphertext, 'iv' => $iv, 'tag' => $tag]; } + /** + * AES-256-GCM decrypt. + */ + private static function aesGcmDecrypt( + string $ciphertext, + string $key, + string $iv, + string $tag, + ?string $aad, + ): string { + $plaintext = openssl_decrypt( + $ciphertext, + 'aes-256-gcm', + $key, + OPENSSL_RAW_DATA, + $iv, + $tag, + $aad ?? '', + ); + + if ($plaintext === false) { + throw new \RuntimeException('AES-GCM decryption failed'); + } + + return $plaintext; + } + + /** + * Encode a 32-bit unsigned integer as LEB128. + */ + private static function encodeU32Leb128(int $value): string + { + if ($value < 0 || $value > 0xFFFFFFFF) { + throw new \InvalidArgumentException('Value must be a 32-bit unsigned integer'); + } + + $encoded = ''; + do { + $byte = $value & 0x7F; + $value >>= 7; + if ($value !== 0) { + $byte |= 0x80; + } + $encoded .= chr($byte); + } while ($value !== 0); + + return $encoded; + } + + /** + * Decode an unsigned LEB128-encoded 32-bit integer. + * + * @return array{0: int, 1: int} [value, bytesConsumed] + */ + private static function decodeU32Leb128(string $buf): array + { + $res = 0; + $bit = 0; + $len = strlen($buf); + for ($i = 0; $i < $len; $i++) { + if ($i > 4) { + throw new \InvalidArgumentException('LEB128 integer overflow'); + } + $b = ord($buf[$i]); + $res |= ($b & 0x7F) << (7 * $bit); + if (($b & 0x80) === 0) { + return [$res, $i + 1]; + } + $bit++; + } + throw new \InvalidArgumentException('LEB128 integer not found'); + } + /** + * Extract IV, tag, keyBlob, and ciphertext from a base64 payload. + * + * Format: [IV:12b][TAG:16b][LEB128 Length][keyBlob][ciphertext] + * + * @return array{iv: string, tag: string, keys: string, ciphertext: string} + */ + private static function decodeEncryptedPayload(string $encryptedDataB64): array + { + $payload = base64_decode($encryptedDataB64, true); + if ($payload === false) { + throw new \InvalidArgumentException('Base64 decoding failed'); + } + + $iv = substr($payload, 0, 12); + $tag = substr($payload, 12, 16); + [$keyLen, $lebLen] = self::decodeU32Leb128(substr($payload, 28)); + $keysIndex = 28 + $lebLen; + $keysEnd = $keysIndex + $keyLen; + $keysSlice = substr($payload, $keysIndex, $keyLen); + $keys = base64_encode($keysSlice); + $ciphertext = substr($payload, $keysEnd); + + return ['iv' => $iv, 'tag' => $tag, 'keys' => $keys, 'ciphertext' => $ciphertext]; + } } diff --git a/lib/Version.php b/lib/Version.php index 04be181b..6ad53338 100644 --- a/lib/Version.php +++ b/lib/Version.php @@ -1,5 +1,8 @@ verifyHeader($sigHeader, $payload, $secret, $tolerance); - - if ($eventResult == 'pass') { - return Resource\Webhook::constructFromPayload($payload); - } else { - return $eventResult; - } - } - - /** - * Verifies the header returned from WorkOS contains a valid timestamp - * no older than 3 minutes, and computes the signature. - * - * @param string $sigHeader WorkOS header containing v1 signature and timestamp - * @param string $payload Body of the webhook - * @param string $secret Webhook secret from the WorkOS dashboard - * @param int $tolerance Number of seconds old the webhook can be before it's invalid - * @return string 'pass' if valid, otherwise an error message - */ - public function verifyHeader($sigHeader, $payload, $secret, $tolerance): string - { - $timestamp = (int) $this->getTimeStamp($sigHeader); - $signature = $this->getSignature($sigHeader); - - $currentTime = time(); - $expectedSignature = $this->computeSignature($timestamp, $payload, $secret); - - if (empty($timestamp)) { - return 'No Timestamp available'; - } elseif (empty($signature)) { - return 'No signature hash found with expected scheme v1'; - } elseif ($timestamp < $currentTime - $tolerance) { - return 'Timestamp outside of tolerance'; - } elseif ($signature != $expectedSignature) { - return 'Constructed signature '.$expectedSignature.'Does not match WorkOS Header Signature '.$signature; - } else { - return 'pass'; - } - } - - /** - * Splits WorkOS header's two values and pulls out timestamp value and returns it - * - * @param string $sigHeader WorkOS header containing v1 signature and timestamp - * @return $timestamp - */ - public function getTimeStamp($sigHeader) - { - $workosHeadersSplit = explode(',', $sigHeader, 2); - $timestamp = substr($workosHeadersSplit[0], 2); - - return $timestamp; - } - - /** - * Splits WorkOS headers two values and pulls out the signature value and returns it - * - * @param string $sigHeader WorkOS header containing v1 signature and timestamp - * @return string - */ - public function getSignature($sigHeader) - { - $workosHeadersSplit = explode(',', $sigHeader, 2); - $signature = substr($workosHeadersSplit[1], 4); - - return $signature; - } - - /** - * Computes a signature for a webhook payload using the provided timestamp and secret - * - * @param int $timestamp Unix timestamp to use in signature - * @param string $payload The payload to sign - * @param string $secret Secret key used for signing - * @return string The computed HMAC SHA-256 signature - */ - public function computeSignature($timestamp, $payload, $secret) - { - $signedPayload = $timestamp . '.' . $payload; - return hash_hmac('sha256', $signedPayload, $secret, false); - } -} diff --git a/lib/WebhookVerification.php b/lib/WebhookVerification.php new file mode 100644 index 00000000..0acd9a0f --- /dev/null +++ b/lib/WebhookVerification.php @@ -0,0 +1,120 @@ +verifyHeader( + eventBody: $eventBody, + eventSignature: $eventSignature, + secret: $secret, + tolerance: $tolerance, + ); + + return json_decode($eventBody, true); + } + + /** + * Verify the signature of a Webhook. Throws if verification fails. + * + * @param string $eventBody The raw webhook body (string). + * @param string $eventSignature The 'WorkOS-Signature' header value. + * @param string $secret The webhook endpoint secret from the WorkOS dashboard. + * @param int|null $tolerance Seconds the event is valid for. Defaults to 180. + * @throws \InvalidArgumentException If the signature cannot be verified. + */ + public function verifyHeader( + string $eventBody, + string $eventSignature, + string $secret, + ?int $tolerance = null, + ): void { + [$issuedTimestamp, $signatureHash] = self::getTimestampAndSignatureHash($eventSignature); + + $maxSeconds = $tolerance ?? self::DEFAULT_TOLERANCE; + $currentTime = time(); + $timestampInSeconds = intval($issuedTimestamp) / 1000; + $secondsSinceIssued = $currentTime - $timestampInSeconds; + + if ($secondsSinceIssued > $maxSeconds) { + throw new \InvalidArgumentException('Timestamp outside the tolerance zone'); + } + + $expectedSignature = self::computeSignature($issuedTimestamp, $eventBody, $secret); + + if (!hash_equals($expectedSignature, $signatureHash)) { + throw new \InvalidArgumentException( + 'Signature hash does not match the expected signature hash for payload' + ); + } + } + + /** + * Parse the timestamp and signature hash from a WorkOS-Signature header. + * + * @param string $sigHeader The 'WorkOS-Signature' header value. + * @return array{0: string, 1: string} [timestamp, signatureHash] + * @throws \InvalidArgumentException If the header cannot be parsed. + */ + public static function getTimestampAndSignatureHash(string $sigHeader): array + { + $parts = explode(', ', $sigHeader); + if (count($parts) !== 2) { + throw new \InvalidArgumentException( + 'Unable to extract timestamp and signature hash from header' + ); + } + + // Format: "t=, v1=" + $timestamp = substr($parts[0], 2); // strip "t=" + $hash = substr($parts[1], 3); // strip "v1=" + + return [$timestamp, $hash]; + } + + /** + * Compute the expected HMAC-SHA256 signature for a webhook payload. + * + * @param string $timestamp The issued timestamp (milliseconds). + * @param string $payload The raw webhook body. + * @param string $secret The webhook secret. + * @return string The hex-encoded HMAC signature. + */ + public static function computeSignature(string $timestamp, string $payload, string $secret): string + { + $unhashedString = "{$timestamp}.{$payload}"; + return hash_hmac('sha256', $unhashedString, $secret); + } +} diff --git a/lib/Widgets.php b/lib/Widgets.php deleted file mode 100644 index 5474c1d8..00000000 --- a/lib/Widgets.php +++ /dev/null @@ -1,36 +0,0 @@ - $organization_id, - "user_id" => $user_id, - "scopes" => $scopes, - ]; - - $response = Client::request(Client::METHOD_POST, $getTokenPath, null, $params, true); - - return Resource\WidgetTokenResponse::constructFromResponse($response); - } -} diff --git a/lib/WorkOS.php b/lib/WorkOS.php index 935e32e3..f849f841 100644 --- a/lib/WorkOS.php +++ b/lib/WorkOS.php @@ -1,165 +1,203 @@ httpClient = new HttpClient($apiKey, $clientId, $baseUrl, $timeout, $maxRetries, $handler); + } - /** - * @return null|string WorkOS API key - */ - public static function getApiKey() + public function apiKeys(): ApiKeys { - if (isset(self::$apiKey)) { - return self::$apiKey; - } + return $this->apiKeys ??= new Service\ApiKeys($this->httpClient); + } - $envValue = self::getEnvVariable("WORKOS_API_KEY"); - if ($envValue) { - self::$apiKey = $envValue; - return self::$apiKey; - } + public function multiFactorAuth(): MultiFactorAuth + { + return $this->multiFactorAuth ??= new Service\MultiFactorAuth($this->httpClient); + } - $msg = "\$apiKey is required"; - throw new \WorkOS\Exception\ConfigurationException($msg); + public function connect(): Connect + { + return $this->connect ??= new Service\Connect($this->httpClient); } - /** - * @param null|string $apiKey WorkOS API key - */ - public static function setApiKey($apiKey) + public function authorization(): Authorization { - self::$apiKey = $apiKey; + return $this->authorization ??= new Service\Authorization($this->httpClient); } - /** - * @throws \WorkOS\Exception\ConfigurationException - * - * @return null|string WorkOS Client ID - */ - public static function getClientId() + public function sso(): SSO { - if (isset(self::$clientId)) { - return self::$clientId; - } + return $this->sso ??= new Service\SSO($this->httpClient); + } - $envValue = self::getEnvVariable("WORKOS_CLIENT_ID"); - if ($envValue) { - self::$clientId = $envValue; - return self::$clientId; - } + public function pipes(): Pipes + { + return $this->pipes ??= new Service\Pipes($this->httpClient); + } - $msg = "\$clientId is required"; - throw new \WorkOS\Exception\ConfigurationException($msg); + public function directorySync(): DirectorySync + { + return $this->directorySync ??= new Service\DirectorySync($this->httpClient); } - /** - * @param string $clientId WorkOS Client ID - */ - public static function setClientId($clientId) + public function events(): Events { - self::$clientId = $clientId; + return $this->events ??= new Service\Events($this->httpClient); } - /** - * @return string WorkOS base API URL - */ - public static function getApiBaseURL() + public function featureFlags(): FeatureFlags { - return self::$apiBaseUrl; + return $this->featureFlags ??= new Service\FeatureFlags($this->httpClient); } - /** - * @param string $apiBaseUrl WorkOS base API URL - */ - public static function setApiBaseUrl($apiBaseUrl) + public function organizationDomains(): OrganizationDomains { - self::$apiBaseUrl = $apiBaseUrl; + return $this->organizationDomains ??= new Service\OrganizationDomains($this->httpClient); } - /** - * @param string $identifier SDK identifier - */ - public static function setIdentifier($identifier) + public function organizations(): Organizations { - self::$identifier = $identifier; + return $this->organizations ??= new Service\Organizations($this->httpClient); } - /** - * @return string SDK identifier - */ - public static function getIdentifier() + public function adminPortal(): AdminPortal { - return self::$identifier; + return $this->adminPortal ??= new Service\AdminPortal($this->httpClient); } - /** - * @param string $version SDK version - */ - public static function setVersion($version) + public function radar(): Radar { - self::$version = $version; + return $this->radar ??= new Service\Radar($this->httpClient); } - /** - * @return string SDK version - */ - public static function getVersion() + public function userManagement(): UserManagement { - return self::$version; + return $this->userManagement ??= new Service\UserManagement($this->httpClient); } - /** - * Get environment variable with fallback to cached config sources. - * Checks in order: getenv(), $_ENV, $_SERVER - * - * @param string $key Environment variable name - * @return string|false The environment variable value or false if not found - */ - private static function getEnvVariable($key) + public function webhooks(): Webhooks { - $value = getenv($key); - if ($value !== false && $value !== '') { - return $value; - } + return $this->webhooks ??= new Service\Webhooks($this->httpClient); + } - if (isset($_ENV[$key]) && $_ENV[$key] !== '') { - return $_ENV[$key]; - } + public function widgets(): Widgets + { + return $this->widgets ??= new Service\Widgets($this->httpClient); + } + + public function auditLogs(): AuditLogs + { + return $this->auditLogs ??= new Service\AuditLogs($this->httpClient); + } + + public function passwordless(): Passwordless + { + return $this->passwordless ??= new Passwordless($this->httpClient); + } + + public function vault(): Vault + { + return $this->vault ??= new Vault($this->httpClient); + } + + public function webhookVerification(): WebhookVerification + { + return $this->webhookVerification ??= new WebhookVerification($this->httpClient); + } + + public function actions(): Actions + { + return $this->actions ??= new Actions($this->httpClient); + } - if (isset($_SERVER[$key]) && $_SERVER[$key] !== '') { - return $_SERVER[$key]; - } + public function sessionManager(): SessionManager + { + return $this->sessionManager ??= new SessionManager($this->httpClient); + } - return false; + public function pkce(): PKCEHelper + { + return $this->pkce ??= new PKCEHelper($this->httpClient); } } diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 00000000..ab3755f1 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,6 @@ +parameters: + level: 5 + paths: + - lib + excludePaths: + - vendor diff --git a/script/ci b/script/ci new file mode 100755 index 00000000..052714b8 --- /dev/null +++ b/script/ci @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_DIR="$(dirname "$SCRIPT_DIR")" + +cd "$PROJECT_DIR" + +if [ ! -d vendor ]; then + echo "Installing dependencies..." + composer install --prefer-dist --no-progress --no-interaction +fi + +echo "==> Checking formatting (php-cs-fixer)..." +php vendor/bin/php-cs-fixer fix -v --dry-run --using-cache=no --config=.php-cs-fixer.dist.php + +echo "" +echo "==> Running typecheck (PHPStan)..." +php vendor/bin/phpstan analyse --no-progress + +echo "" +echo "==> Running tests (PHPUnit)..." +php vendor/bin/phpunit + +echo "" +echo "All checks passed." diff --git a/tests/ActionsTest.php b/tests/ActionsTest.php new file mode 100644 index 00000000..56a05515 --- /dev/null +++ b/tests/ActionsTest.php @@ -0,0 +1,91 @@ +createMockClient([]); + // Should not throw + $client->actions()->verifyHeader($payload, $sigHeader, self::SECRET); + $this->assertTrue(true); + } + + public function testVerifyHeaderInvalidSignature(): void + { + $payload = '{"action":"authentication"}'; + $timestamp = (string) (time() * 1000); + $sigHeader = "t={$timestamp}, v1=invalidsig"; + + $client = $this->createMockClient([]); + $this->expectException(\InvalidArgumentException::class); + $client->actions()->verifyHeader($payload, $sigHeader, self::SECRET); + } + + public function testConstructAction(): void + { + $payload = '{"action":"authentication","data":{"user_id":"usr_123"}}'; + $timestamp = (string) (time() * 1000); + $expectedSig = hash_hmac('sha256', "{$timestamp}.{$payload}", self::SECRET); + $sigHeader = "t={$timestamp}, v1={$expectedSig}"; + + $client = $this->createMockClient([]); + $result = $client->actions()->constructAction($payload, $sigHeader, self::SECRET); + $this->assertSame('authentication', $result['action']); + $this->assertSame('usr_123', $result['data']['user_id']); + } + + public function testSignResponse(): void + { + $client = $this->createMockClient([]); + $result = $client->actions()->signResponse( + actionType: 'authentication', + verdict: 'Allow', + secret: self::SECRET, + ); + + $this->assertSame('authentication_action_response', $result['object']); + $this->assertSame('Allow', $result['payload']['verdict']); + $this->assertArrayHasKey('signature', $result); + $this->assertArrayHasKey('timestamp', $result['payload']); + } + + public function testSignResponseWithDeny(): void + { + $client = $this->createMockClient([]); + $result = $client->actions()->signResponse( + actionType: 'user_registration', + verdict: 'Deny', + secret: self::SECRET, + errorMessage: 'Registration blocked', + ); + + $this->assertSame('user_registration_action_response', $result['object']); + $this->assertSame('Deny', $result['payload']['verdict']); + $this->assertSame('Registration blocked', $result['payload']['error_message']); + } + + public function testActionsAccessibleFromClient(): void + { + $client = $this->createMockClient([]); + $this->assertInstanceOf(Actions::class, $client->actions()); + } +} diff --git a/tests/ClientTest.php b/tests/ClientTest.php new file mode 100644 index 00000000..35cb532c --- /dev/null +++ b/tests/ClientTest.php @@ -0,0 +1,19 @@ +assertNotNull($client); + } +} diff --git a/tests/Fixtures/action_authentication_denied.json b/tests/Fixtures/action_authentication_denied.json new file mode 100644 index 00000000..51af3e3d --- /dev/null +++ b/tests/Fixtures/action_authentication_denied.json @@ -0,0 +1,37 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "action.authentication.denied", + "data": { + "action_endpoint_id": "action_endpoint_01EHWNCE74X7JSDV0X3SZ3KJNY", + "action_execution_id": "action_execution_01EHWNCE74X7JSDV0X3SZ3KJNY", + "type": "authentication", + "verdict": "Deny", + "user_id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "email": "user@example.com", + "ip_address": "203.0.113.1", + "user_agent": "Mozilla/5.0" + }, + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "created_at": "2026-01-15T12:00:00.000Z", + "object": "event" +} diff --git a/tests/Fixtures/action_authentication_denied_context.json b/tests/Fixtures/action_authentication_denied_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/action_authentication_denied_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/action_authentication_denied_context_actor.json b/tests/Fixtures/action_authentication_denied_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/action_authentication_denied_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/action_authentication_denied_context_google_analytics_session.json b/tests/Fixtures/action_authentication_denied_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/action_authentication_denied_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/action_authentication_denied_data.json b/tests/Fixtures/action_authentication_denied_data.json new file mode 100644 index 00000000..274482f9 --- /dev/null +++ b/tests/Fixtures/action_authentication_denied_data.json @@ -0,0 +1,11 @@ +{ + "action_endpoint_id": "action_endpoint_01EHWNCE74X7JSDV0X3SZ3KJNY", + "action_execution_id": "action_execution_01EHWNCE74X7JSDV0X3SZ3KJNY", + "type": "authentication", + "verdict": "Deny", + "user_id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "email": "user@example.com", + "ip_address": "203.0.113.1", + "user_agent": "Mozilla/5.0" +} diff --git a/tests/Fixtures/action_user_registration_denied.json b/tests/Fixtures/action_user_registration_denied.json new file mode 100644 index 00000000..bb52ecbb --- /dev/null +++ b/tests/Fixtures/action_user_registration_denied.json @@ -0,0 +1,36 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "action.user_registration.denied", + "data": { + "action_endpoint_id": "action_endpoint_01EHWNCE74X7JSDV0X3SZ3KJNY", + "action_execution_id": "action_execution_01EHWNCE74X7JSDV0X3SZ3KJNY", + "type": "user_registration", + "verdict": "Deny", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "email": "user@example.com", + "ip_address": "203.0.113.1", + "user_agent": "Mozilla/5.0" + }, + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "created_at": "2026-01-15T12:00:00.000Z", + "object": "event" +} diff --git a/tests/Fixtures/action_user_registration_denied_context.json b/tests/Fixtures/action_user_registration_denied_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/action_user_registration_denied_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/action_user_registration_denied_context_actor.json b/tests/Fixtures/action_user_registration_denied_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/action_user_registration_denied_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/action_user_registration_denied_context_google_analytics_session.json b/tests/Fixtures/action_user_registration_denied_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/action_user_registration_denied_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/action_user_registration_denied_data.json b/tests/Fixtures/action_user_registration_denied_data.json new file mode 100644 index 00000000..ac10d76d --- /dev/null +++ b/tests/Fixtures/action_user_registration_denied_data.json @@ -0,0 +1,10 @@ +{ + "action_endpoint_id": "action_endpoint_01EHWNCE74X7JSDV0X3SZ3KJNY", + "action_execution_id": "action_execution_01EHWNCE74X7JSDV0X3SZ3KJNY", + "type": "user_registration", + "verdict": "Deny", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "email": "user@example.com", + "ip_address": "203.0.113.1", + "user_agent": "Mozilla/5.0" +} diff --git a/tests/Fixtures/add_role_permission.json b/tests/Fixtures/add_role_permission.json new file mode 100644 index 00000000..8dd80ea6 --- /dev/null +++ b/tests/Fixtures/add_role_permission.json @@ -0,0 +1,3 @@ +{ + "slug": "reports:export" +} diff --git a/tests/Fixtures/api_key.json b/tests/Fixtures/api_key.json new file mode 100644 index 00000000..e05b1db2 --- /dev/null +++ b/tests/Fixtures/api_key.json @@ -0,0 +1,17 @@ +{ + "object": "api_key", + "id": "api_key_01EHZNVPK3SFK441A1RGBFSHRT", + "owner": { + "type": "organization", + "id": "org_01EHZNVPK3SFK441A1RGBFSHRT" + }, + "name": "Production API Key", + "obfuscated_value": "sk_...3456", + "last_used_at": null, + "permissions": [ + "posts:read", + "posts:write" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/api_key_created.json b/tests/Fixtures/api_key_created.json new file mode 100644 index 00000000..f98c97d6 --- /dev/null +++ b/tests/Fixtures/api_key_created.json @@ -0,0 +1,43 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "api_key.created", + "data": { + "object": "api_key", + "id": "api_key_01EHWNCE74X7JSDV0X3SZ3KJNY", + "owner": { + "type": "organization", + "id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY" + }, + "name": "My API Key", + "obfuscated_value": "sk_test_...1234", + "last_used_at": "2026-01-15T12:00:00.000Z", + "permissions": [ + "users:read", + "users:write" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/api_key_created_context.json b/tests/Fixtures/api_key_created_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/api_key_created_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/api_key_created_context_actor.json b/tests/Fixtures/api_key_created_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/api_key_created_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/api_key_created_context_google_analytics_session.json b/tests/Fixtures/api_key_created_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/api_key_created_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/api_key_created_data.json b/tests/Fixtures/api_key_created_data.json new file mode 100644 index 00000000..1f0a1945 --- /dev/null +++ b/tests/Fixtures/api_key_created_data.json @@ -0,0 +1,17 @@ +{ + "object": "api_key", + "id": "api_key_01EHWNCE74X7JSDV0X3SZ3KJNY", + "owner": { + "type": "organization", + "id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY" + }, + "name": "My API Key", + "obfuscated_value": "sk_test_...1234", + "last_used_at": "2026-01-15T12:00:00.000Z", + "permissions": [ + "users:read", + "users:write" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/api_key_created_data_owner.json b/tests/Fixtures/api_key_created_data_owner.json new file mode 100644 index 00000000..482d9913 --- /dev/null +++ b/tests/Fixtures/api_key_created_data_owner.json @@ -0,0 +1,4 @@ +{ + "type": "organization", + "id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY" +} diff --git a/tests/Fixtures/api_key_list_list_metadata.json b/tests/Fixtures/api_key_list_list_metadata.json new file mode 100644 index 00000000..574196f6 --- /dev/null +++ b/tests/Fixtures/api_key_list_list_metadata.json @@ -0,0 +1,4 @@ +{ + "before": "api_key_01HXYZ123456789ABCDEFGHIJ", + "after": "api_key_01HXYZ987654321KJIHGFEDCBA" +} diff --git a/tests/Fixtures/api_key_owner.json b/tests/Fixtures/api_key_owner.json new file mode 100644 index 00000000..ddbfe81d --- /dev/null +++ b/tests/Fixtures/api_key_owner.json @@ -0,0 +1,4 @@ +{ + "type": "organization", + "id": "org_01EHZNVPK3SFK441A1RGBFSHRT" +} diff --git a/tests/Fixtures/api_key_revoked.json b/tests/Fixtures/api_key_revoked.json new file mode 100644 index 00000000..859ccb36 --- /dev/null +++ b/tests/Fixtures/api_key_revoked.json @@ -0,0 +1,43 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "api_key.revoked", + "data": { + "object": "api_key", + "id": "api_key_01EHWNCE74X7JSDV0X3SZ3KJNY", + "owner": { + "type": "organization", + "id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY" + }, + "name": "My API Key", + "obfuscated_value": "sk_test_...1234", + "last_used_at": "2026-01-15T12:00:00.000Z", + "permissions": [ + "users:read", + "users:write" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/api_key_revoked_context.json b/tests/Fixtures/api_key_revoked_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/api_key_revoked_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/api_key_revoked_context_actor.json b/tests/Fixtures/api_key_revoked_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/api_key_revoked_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/api_key_revoked_context_google_analytics_session.json b/tests/Fixtures/api_key_revoked_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/api_key_revoked_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/api_key_revoked_data.json b/tests/Fixtures/api_key_revoked_data.json new file mode 100644 index 00000000..1f0a1945 --- /dev/null +++ b/tests/Fixtures/api_key_revoked_data.json @@ -0,0 +1,17 @@ +{ + "object": "api_key", + "id": "api_key_01EHWNCE74X7JSDV0X3SZ3KJNY", + "owner": { + "type": "organization", + "id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY" + }, + "name": "My API Key", + "obfuscated_value": "sk_test_...1234", + "last_used_at": "2026-01-15T12:00:00.000Z", + "permissions": [ + "users:read", + "users:write" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/api_key_revoked_data_owner.json b/tests/Fixtures/api_key_revoked_data_owner.json new file mode 100644 index 00000000..482d9913 --- /dev/null +++ b/tests/Fixtures/api_key_revoked_data_owner.json @@ -0,0 +1,4 @@ +{ + "type": "organization", + "id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY" +} diff --git a/tests/Fixtures/api_key_validation_response.json b/tests/Fixtures/api_key_validation_response.json new file mode 100644 index 00000000..1e77554f --- /dev/null +++ b/tests/Fixtures/api_key_validation_response.json @@ -0,0 +1,19 @@ +{ + "api_key": { + "object": "api_key", + "id": "api_key_01EHZNVPK3SFK441A1RGBFSHRT", + "owner": { + "type": "organization", + "id": "org_01EHZNVPK3SFK441A1RGBFSHRT" + }, + "name": "Production API Key", + "obfuscated_value": "sk_...3456", + "last_used_at": null, + "permissions": [ + "posts:read", + "posts:write" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } +} diff --git a/tests/Fixtures/api_key_with_value.json b/tests/Fixtures/api_key_with_value.json new file mode 100644 index 00000000..9c85f194 --- /dev/null +++ b/tests/Fixtures/api_key_with_value.json @@ -0,0 +1,18 @@ +{ + "object": "api_key", + "id": "api_key_01EHZNVPK3SFK441A1RGBFSHRT", + "owner": { + "type": "organization", + "id": "org_01EHZNVPK3SFK441A1RGBFSHRT" + }, + "name": "Production API Key", + "obfuscated_value": "sk_...3456", + "last_used_at": null, + "permissions": [ + "posts:read", + "posts:write" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "value": "sk_abcdefghijklmnop123456" +} diff --git a/tests/Fixtures/api_key_with_value_owner.json b/tests/Fixtures/api_key_with_value_owner.json new file mode 100644 index 00000000..ddbfe81d --- /dev/null +++ b/tests/Fixtures/api_key_with_value_owner.json @@ -0,0 +1,4 @@ +{ + "type": "organization", + "id": "org_01EHZNVPK3SFK441A1RGBFSHRT" +} diff --git a/tests/Fixtures/application_credentials_list_item.json b/tests/Fixtures/application_credentials_list_item.json new file mode 100644 index 00000000..4c03cc2e --- /dev/null +++ b/tests/Fixtures/application_credentials_list_item.json @@ -0,0 +1,8 @@ +{ + "object": "connect_application_secret", + "id": "secret_01J9Q2Z3X4Y5W6V7U8T9S0R1Q", + "secret_hint": "abc123", + "last_used_at": null, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/assign_role.json b/tests/Fixtures/assign_role.json new file mode 100644 index 00000000..66cab23c --- /dev/null +++ b/tests/Fixtures/assign_role.json @@ -0,0 +1,6 @@ +{ + "role_slug": "editor", + "resource_id": "authz_resource_01HXYZ123456789ABCDEFGH", + "resource_external_id": "project-ext-456", + "resource_type_slug": "project" +} diff --git a/tests/Fixtures/audit_log_action_json.json b/tests/Fixtures/audit_log_action_json.json new file mode 100644 index 00000000..a7212b6c --- /dev/null +++ b/tests/Fixtures/audit_log_action_json.json @@ -0,0 +1,42 @@ +{ + "object": "audit_log_action", + "name": "user.viewed_invoice", + "schema": { + "object": "audit_log_schema", + "version": 1, + "actor": { + "metadata": { + "type": "object", + "properties": { + "role": { + "type": "string" + } + } + } + }, + "targets": [ + { + "type": "invoice", + "metadata": { + "type": "object", + "properties": { + "cost": { + "type": "number" + } + } + } + } + ], + "metadata": { + "type": "object", + "properties": { + "transactionId": { + "type": "string" + } + } + }, + "created_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/audit_log_configuration.json b/tests/Fixtures/audit_log_configuration.json new file mode 100644 index 00000000..fd33f456 --- /dev/null +++ b/tests/Fixtures/audit_log_configuration.json @@ -0,0 +1,12 @@ +{ + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", + "retention_period_in_days": 30, + "state": "active", + "log_stream": { + "id": "als_01EHZNVPK3SFK441A1RGBFSHRT", + "type": "Datadog", + "state": "active", + "last_synced_at": "2026-01-15T12:00:00.000Z", + "created_at": "2026-01-15T12:00:00.000Z" + } +} diff --git a/tests/Fixtures/audit_log_configuration_log_stream.json b/tests/Fixtures/audit_log_configuration_log_stream.json new file mode 100644 index 00000000..c108bda9 --- /dev/null +++ b/tests/Fixtures/audit_log_configuration_log_stream.json @@ -0,0 +1,7 @@ +{ + "id": "als_01EHZNVPK3SFK441A1RGBFSHRT", + "type": "Datadog", + "state": "active", + "last_synced_at": "2026-01-15T12:00:00.000Z", + "created_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/audit_log_event.json b/tests/Fixtures/audit_log_event.json new file mode 100644 index 00000000..ab6e39e7 --- /dev/null +++ b/tests/Fixtures/audit_log_event.json @@ -0,0 +1,30 @@ +{ + "action": "user.signed_in", + "occurred_at": "2026-02-02T16:35:39.317Z", + "actor": { + "id": "user_TF4C5938", + "type": "user", + "name": "Jon Smith", + "metadata": { + "owner": "user_01GBTCQ2" + } + }, + "targets": [ + { + "id": "user_TF4C5938", + "type": "user", + "name": "Jon Smith", + "metadata": { + "owner": "user_01GBTCQ2" + } + } + ], + "context": { + "location": "123.123.123.123", + "user_agent": "Chrome/104.0.0.0" + }, + "metadata": { + "owner": "user_01GBTCQ2" + }, + "version": 1 +} diff --git a/tests/Fixtures/audit_log_event_actor.json b/tests/Fixtures/audit_log_event_actor.json new file mode 100644 index 00000000..68894d0d --- /dev/null +++ b/tests/Fixtures/audit_log_event_actor.json @@ -0,0 +1,8 @@ +{ + "id": "user_TF4C5938", + "type": "user", + "name": "Jon Smith", + "metadata": { + "owner": "user_01GBTCQ2" + } +} diff --git a/tests/Fixtures/audit_log_event_context.json b/tests/Fixtures/audit_log_event_context.json new file mode 100644 index 00000000..4b61b917 --- /dev/null +++ b/tests/Fixtures/audit_log_event_context.json @@ -0,0 +1,4 @@ +{ + "location": "123.123.123.123", + "user_agent": "Chrome/104.0.0.0" +} diff --git a/tests/Fixtures/audit_log_event_create_response.json b/tests/Fixtures/audit_log_event_create_response.json new file mode 100644 index 00000000..5550c6db --- /dev/null +++ b/tests/Fixtures/audit_log_event_create_response.json @@ -0,0 +1,3 @@ +{ + "success": true +} diff --git a/tests/Fixtures/audit_log_event_ingestion.json b/tests/Fixtures/audit_log_event_ingestion.json new file mode 100644 index 00000000..09c9f490 --- /dev/null +++ b/tests/Fixtures/audit_log_event_ingestion.json @@ -0,0 +1,33 @@ +{ + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "event": { + "action": "user.signed_in", + "occurred_at": "2026-02-02T16:35:39.317Z", + "actor": { + "id": "user_TF4C5938", + "type": "user", + "name": "Jon Smith", + "metadata": { + "owner": "user_01GBTCQ2" + } + }, + "targets": [ + { + "id": "user_TF4C5938", + "type": "user", + "name": "Jon Smith", + "metadata": { + "owner": "user_01GBTCQ2" + } + } + ], + "context": { + "location": "123.123.123.123", + "user_agent": "Chrome/104.0.0.0" + }, + "metadata": { + "owner": "user_01GBTCQ2" + }, + "version": 1 + } +} diff --git a/tests/Fixtures/audit_log_event_target.json b/tests/Fixtures/audit_log_event_target.json new file mode 100644 index 00000000..68894d0d --- /dev/null +++ b/tests/Fixtures/audit_log_event_target.json @@ -0,0 +1,8 @@ +{ + "id": "user_TF4C5938", + "type": "user", + "name": "Jon Smith", + "metadata": { + "owner": "user_01GBTCQ2" + } +} diff --git a/tests/Fixtures/audit_log_export_creation.json b/tests/Fixtures/audit_log_export_creation.json new file mode 100644 index 00000000..8897537d --- /dev/null +++ b/tests/Fixtures/audit_log_export_creation.json @@ -0,0 +1,20 @@ +{ + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", + "range_start": "2022-07-02T18:09:06.996Z", + "range_end": "2022-09-02T18:09:06.996Z", + "actions": [ + "user.signed_in" + ], + "actors": [ + "Jon Smith" + ], + "actor_names": [ + "Jon Smith" + ], + "actor_ids": [ + "user_01GBZK5MP7TD1YCFQHFR22180V" + ], + "targets": [ + "team" + ] +} diff --git a/tests/Fixtures/audit_log_export_json.json b/tests/Fixtures/audit_log_export_json.json new file mode 100644 index 00000000..e076643f --- /dev/null +++ b/tests/Fixtures/audit_log_export_json.json @@ -0,0 +1,8 @@ +{ + "object": "audit_log_export", + "id": "audit_log_export_01GBZK5MP7TD1YCFQHFR22180V", + "state": "ready", + "url": "https://exports.audit-logs.com/audit-log-exports/export.csv", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/audit_log_schema.json b/tests/Fixtures/audit_log_schema.json new file mode 100644 index 00000000..773d6b72 --- /dev/null +++ b/tests/Fixtures/audit_log_schema.json @@ -0,0 +1,33 @@ +{ + "actor": { + "metadata": { + "type": "object", + "properties": { + "role": { + "type": "string" + } + } + } + }, + "targets": [ + { + "type": "invoice", + "metadata": { + "type": "object", + "properties": { + "cost": { + "type": "number" + } + } + } + } + ], + "metadata": { + "type": "object", + "properties": { + "transactionId": { + "type": "string" + } + } + } +} diff --git a/tests/Fixtures/audit_log_schema_actor.json b/tests/Fixtures/audit_log_schema_actor.json new file mode 100644 index 00000000..cea87599 --- /dev/null +++ b/tests/Fixtures/audit_log_schema_actor.json @@ -0,0 +1,10 @@ +{ + "metadata": { + "type": "object", + "properties": { + "role": { + "type": "string" + } + } + } +} diff --git a/tests/Fixtures/audit_log_schema_json.json b/tests/Fixtures/audit_log_schema_json.json new file mode 100644 index 00000000..cdf6f075 --- /dev/null +++ b/tests/Fixtures/audit_log_schema_json.json @@ -0,0 +1,36 @@ +{ + "object": "audit_log_schema", + "version": 1, + "actor": { + "metadata": { + "type": "object", + "properties": { + "role": { + "type": "string" + } + } + } + }, + "targets": [ + { + "type": "invoice", + "metadata": { + "type": "object", + "properties": { + "cost": { + "type": "number" + } + } + } + } + ], + "metadata": { + "type": "object", + "properties": { + "transactionId": { + "type": "string" + } + } + }, + "created_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/audit_log_schema_json_actor.json b/tests/Fixtures/audit_log_schema_json_actor.json new file mode 100644 index 00000000..319068e7 --- /dev/null +++ b/tests/Fixtures/audit_log_schema_json_actor.json @@ -0,0 +1,5 @@ +{ + "metadata": { + "key": {} + } +} diff --git a/tests/Fixtures/audit_log_schema_json_target.json b/tests/Fixtures/audit_log_schema_json_target.json new file mode 100644 index 00000000..328b5256 --- /dev/null +++ b/tests/Fixtures/audit_log_schema_json_target.json @@ -0,0 +1,11 @@ +{ + "type": "invoice", + "metadata": { + "type": "object", + "properties": { + "cost": { + "type": "number" + } + } + } +} diff --git a/tests/Fixtures/audit_log_schema_target.json b/tests/Fixtures/audit_log_schema_target.json new file mode 100644 index 00000000..328b5256 --- /dev/null +++ b/tests/Fixtures/audit_log_schema_target.json @@ -0,0 +1,11 @@ +{ + "type": "invoice", + "metadata": { + "type": "object", + "properties": { + "cost": { + "type": "number" + } + } + } +} diff --git a/tests/Fixtures/audit_logs_retention_json.json b/tests/Fixtures/audit_logs_retention_json.json new file mode 100644 index 00000000..0720427e --- /dev/null +++ b/tests/Fixtures/audit_logs_retention_json.json @@ -0,0 +1,3 @@ +{ + "retention_period_in_days": 30 +} diff --git a/tests/Fixtures/authenticate_response.json b/tests/Fixtures/authenticate_response.json new file mode 100644 index 00000000..5127ae3f --- /dev/null +++ b/tests/Fixtures/authenticate_response.json @@ -0,0 +1,39 @@ +{ + "user": { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": true, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": { + "timezone": "America/New_York" + }, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "organization_id": "org_01H945H0YD4F97JN9MATX7BYAG", + "authkit_authorization_code": "authkit_authz_code_abc123", + "access_token": "eyJhb.nNzb19vaWRjX2tleV9.lc5Uk4yWVk5In0", + "refresh_token": "yAjhKk123NLIjdrBdGZPf8pLIDvK", + "authentication_method": "SSO", + "impersonator": { + "email": "admin@foocorp.com", + "reason": "Investigating an issue with the customer's account." + }, + "oauth_tokens": { + "provider": "GoogleOAuth", + "refresh_token": "1//04g...", + "access_token": "ya29.a0ARrdaM...", + "expires_at": 1735141800, + "scopes": [ + "profile", + "email", + "openid" + ] + } +} diff --git a/tests/Fixtures/authenticate_response_impersonator.json b/tests/Fixtures/authenticate_response_impersonator.json new file mode 100644 index 00000000..b483e3f0 --- /dev/null +++ b/tests/Fixtures/authenticate_response_impersonator.json @@ -0,0 +1,4 @@ +{ + "email": "admin@foocorp.com", + "reason": "Investigating an issue with the customer's account." +} diff --git a/tests/Fixtures/authenticate_response_oauth_token.json b/tests/Fixtures/authenticate_response_oauth_token.json new file mode 100644 index 00000000..014b78c6 --- /dev/null +++ b/tests/Fixtures/authenticate_response_oauth_token.json @@ -0,0 +1,11 @@ +{ + "provider": "GoogleOAuth", + "refresh_token": "1//04g...", + "access_token": "ya29.a0ARrdaM...", + "expires_at": 1735141800, + "scopes": [ + "profile", + "email", + "openid" + ] +} diff --git a/tests/Fixtures/authentication_challenge.json b/tests/Fixtures/authentication_challenge.json new file mode 100644 index 00000000..24e9becd --- /dev/null +++ b/tests/Fixtures/authentication_challenge.json @@ -0,0 +1,9 @@ +{ + "object": "authentication_challenge", + "id": "auth_challenge_01FVYZ5QM8N98T9ME5BCB2BBMJ", + "expires_at": "2026-01-15T12:00:00.000Z", + "code": "123456", + "authentication_factor_id": "auth_factor_01FVYZ5QM8N98T9ME5BCB2BBMJ", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/authentication_challenge_verify_response.json b/tests/Fixtures/authentication_challenge_verify_response.json new file mode 100644 index 00000000..e5f7ceca --- /dev/null +++ b/tests/Fixtures/authentication_challenge_verify_response.json @@ -0,0 +1,12 @@ +{ + "challenge": { + "object": "authentication_challenge", + "id": "auth_challenge_01FVYZ5QM8N98T9ME5BCB2BBMJ", + "expires_at": "2026-01-15T12:00:00.000Z", + "code": "123456", + "authentication_factor_id": "auth_factor_01FVYZ5QM8N98T9ME5BCB2BBMJ", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "valid": true +} diff --git a/tests/Fixtures/authentication_challenges_verify_request.json b/tests/Fixtures/authentication_challenges_verify_request.json new file mode 100644 index 00000000..736bf40a --- /dev/null +++ b/tests/Fixtures/authentication_challenges_verify_request.json @@ -0,0 +1,3 @@ +{ + "code": "123456" +} diff --git a/tests/Fixtures/authentication_email_verification_failed.json b/tests/Fixtures/authentication_email_verification_failed.json new file mode 100644 index 00000000..9115ce3b --- /dev/null +++ b/tests/Fixtures/authentication_email_verification_failed.json @@ -0,0 +1,38 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "authentication.email_verification_failed", + "data": { + "type": "email_verification", + "status": "failed", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com", + "error": { + "code": "mfa_challenge_failed", + "message": "The MFA challenge has failed." + } + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/authentication_email_verification_failed_context.json b/tests/Fixtures/authentication_email_verification_failed_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/authentication_email_verification_failed_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/authentication_email_verification_failed_context_actor.json b/tests/Fixtures/authentication_email_verification_failed_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/authentication_email_verification_failed_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/authentication_email_verification_failed_context_google_analytics_session.json b/tests/Fixtures/authentication_email_verification_failed_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/authentication_email_verification_failed_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/authentication_email_verification_failed_data.json b/tests/Fixtures/authentication_email_verification_failed_data.json new file mode 100644 index 00000000..fead1987 --- /dev/null +++ b/tests/Fixtures/authentication_email_verification_failed_data.json @@ -0,0 +1,12 @@ +{ + "type": "email_verification", + "status": "failed", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com", + "error": { + "code": "mfa_challenge_failed", + "message": "The MFA challenge has failed." + } +} diff --git a/tests/Fixtures/authentication_email_verification_failed_data_error.json b/tests/Fixtures/authentication_email_verification_failed_data_error.json new file mode 100644 index 00000000..8729bbbf --- /dev/null +++ b/tests/Fixtures/authentication_email_verification_failed_data_error.json @@ -0,0 +1,4 @@ +{ + "code": "mfa_challenge_failed", + "message": "The MFA challenge has failed." +} diff --git a/tests/Fixtures/authentication_email_verification_succeeded.json b/tests/Fixtures/authentication_email_verification_succeeded.json new file mode 100644 index 00000000..91e1484e --- /dev/null +++ b/tests/Fixtures/authentication_email_verification_succeeded.json @@ -0,0 +1,34 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "authentication.email_verification_succeeded", + "data": { + "type": "email_verification", + "status": "succeeded", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/authentication_email_verification_succeeded_context.json b/tests/Fixtures/authentication_email_verification_succeeded_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/authentication_email_verification_succeeded_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/authentication_email_verification_succeeded_context_actor.json b/tests/Fixtures/authentication_email_verification_succeeded_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/authentication_email_verification_succeeded_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/authentication_email_verification_succeeded_context_google_analytics_session.json b/tests/Fixtures/authentication_email_verification_succeeded_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/authentication_email_verification_succeeded_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/authentication_email_verification_succeeded_data.json b/tests/Fixtures/authentication_email_verification_succeeded_data.json new file mode 100644 index 00000000..88eeba9b --- /dev/null +++ b/tests/Fixtures/authentication_email_verification_succeeded_data.json @@ -0,0 +1,8 @@ +{ + "type": "email_verification", + "status": "succeeded", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com" +} diff --git a/tests/Fixtures/authentication_factor.json b/tests/Fixtures/authentication_factor.json new file mode 100644 index 00000000..59d80419 --- /dev/null +++ b/tests/Fixtures/authentication_factor.json @@ -0,0 +1,15 @@ +{ + "object": "authentication_factor", + "id": "auth_factor_01FVYZ5QM8N98T9ME5BCB2BBMJ", + "type": "totp", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "sms": { + "phone_number": "+15005550006" + }, + "totp": { + "issuer": "WorkOS", + "user": "user@example.com" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/authentication_factor_enrolled.json b/tests/Fixtures/authentication_factor_enrolled.json new file mode 100644 index 00000000..cf2b1cef --- /dev/null +++ b/tests/Fixtures/authentication_factor_enrolled.json @@ -0,0 +1,18 @@ +{ + "object": "authentication_factor", + "id": "auth_factor_01FVYZ5QM8N98T9ME5BCB2BBMJ", + "type": "totp", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "sms": { + "phone_number": "+15005550006" + }, + "totp": { + "issuer": "WorkOS", + "user": "user@example.com", + "secret": "JBSWY3DPEHPK3PXP", + "qr_code": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...", + "uri": "otpauth://totp/WorkOS:user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=WorkOS" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/authentication_factor_enrolled_sms.json b/tests/Fixtures/authentication_factor_enrolled_sms.json new file mode 100644 index 00000000..6b6f6880 --- /dev/null +++ b/tests/Fixtures/authentication_factor_enrolled_sms.json @@ -0,0 +1,3 @@ +{ + "phone_number": "+15005550006" +} diff --git a/tests/Fixtures/authentication_factor_enrolled_totp.json b/tests/Fixtures/authentication_factor_enrolled_totp.json new file mode 100644 index 00000000..021cf1b6 --- /dev/null +++ b/tests/Fixtures/authentication_factor_enrolled_totp.json @@ -0,0 +1,7 @@ +{ + "issuer": "WorkOS", + "user": "user@example.com", + "secret": "JBSWY3DPEHPK3PXP", + "qr_code": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...", + "uri": "otpauth://totp/WorkOS:user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=WorkOS" +} diff --git a/tests/Fixtures/authentication_factor_sms.json b/tests/Fixtures/authentication_factor_sms.json new file mode 100644 index 00000000..6b6f6880 --- /dev/null +++ b/tests/Fixtures/authentication_factor_sms.json @@ -0,0 +1,3 @@ +{ + "phone_number": "+15005550006" +} diff --git a/tests/Fixtures/authentication_factor_totp.json b/tests/Fixtures/authentication_factor_totp.json new file mode 100644 index 00000000..14ea6dc0 --- /dev/null +++ b/tests/Fixtures/authentication_factor_totp.json @@ -0,0 +1,4 @@ +{ + "issuer": "WorkOS", + "user": "user@example.com" +} diff --git a/tests/Fixtures/authentication_factors_create_request.json b/tests/Fixtures/authentication_factors_create_request.json new file mode 100644 index 00000000..fdc9a408 --- /dev/null +++ b/tests/Fixtures/authentication_factors_create_request.json @@ -0,0 +1,7 @@ +{ + "type": "totp", + "phone_number": "+15555555555", + "totp_issuer": "Foo Corp", + "totp_user": "alan.turing@example.com", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5" +} diff --git a/tests/Fixtures/authentication_magic_auth_failed.json b/tests/Fixtures/authentication_magic_auth_failed.json new file mode 100644 index 00000000..20bb715f --- /dev/null +++ b/tests/Fixtures/authentication_magic_auth_failed.json @@ -0,0 +1,38 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "authentication.magic_auth_failed", + "data": { + "type": "magic_auth", + "status": "failed", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com", + "error": { + "code": "mfa_challenge_failed", + "message": "The MFA challenge has failed." + } + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/authentication_magic_auth_failed_context.json b/tests/Fixtures/authentication_magic_auth_failed_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/authentication_magic_auth_failed_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/authentication_magic_auth_failed_context_actor.json b/tests/Fixtures/authentication_magic_auth_failed_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/authentication_magic_auth_failed_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/authentication_magic_auth_failed_context_google_analytics_session.json b/tests/Fixtures/authentication_magic_auth_failed_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/authentication_magic_auth_failed_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/authentication_magic_auth_failed_data.json b/tests/Fixtures/authentication_magic_auth_failed_data.json new file mode 100644 index 00000000..00bff036 --- /dev/null +++ b/tests/Fixtures/authentication_magic_auth_failed_data.json @@ -0,0 +1,12 @@ +{ + "type": "magic_auth", + "status": "failed", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com", + "error": { + "code": "mfa_challenge_failed", + "message": "The MFA challenge has failed." + } +} diff --git a/tests/Fixtures/authentication_magic_auth_failed_data_error.json b/tests/Fixtures/authentication_magic_auth_failed_data_error.json new file mode 100644 index 00000000..8729bbbf --- /dev/null +++ b/tests/Fixtures/authentication_magic_auth_failed_data_error.json @@ -0,0 +1,4 @@ +{ + "code": "mfa_challenge_failed", + "message": "The MFA challenge has failed." +} diff --git a/tests/Fixtures/authentication_magic_auth_succeeded.json b/tests/Fixtures/authentication_magic_auth_succeeded.json new file mode 100644 index 00000000..9d6aa527 --- /dev/null +++ b/tests/Fixtures/authentication_magic_auth_succeeded.json @@ -0,0 +1,34 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "authentication.magic_auth_succeeded", + "data": { + "type": "magic_auth", + "status": "succeeded", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/authentication_magic_auth_succeeded_context.json b/tests/Fixtures/authentication_magic_auth_succeeded_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/authentication_magic_auth_succeeded_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/authentication_magic_auth_succeeded_context_actor.json b/tests/Fixtures/authentication_magic_auth_succeeded_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/authentication_magic_auth_succeeded_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/authentication_magic_auth_succeeded_context_google_analytics_session.json b/tests/Fixtures/authentication_magic_auth_succeeded_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/authentication_magic_auth_succeeded_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/authentication_magic_auth_succeeded_data.json b/tests/Fixtures/authentication_magic_auth_succeeded_data.json new file mode 100644 index 00000000..81ba032a --- /dev/null +++ b/tests/Fixtures/authentication_magic_auth_succeeded_data.json @@ -0,0 +1,8 @@ +{ + "type": "magic_auth", + "status": "succeeded", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com" +} diff --git a/tests/Fixtures/authentication_mfa_failed.json b/tests/Fixtures/authentication_mfa_failed.json new file mode 100644 index 00000000..624ebfca --- /dev/null +++ b/tests/Fixtures/authentication_mfa_failed.json @@ -0,0 +1,38 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "authentication.mfa_failed", + "data": { + "type": "mfa", + "status": "failed", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com", + "error": { + "code": "mfa_challenge_failed", + "message": "The MFA challenge has failed." + } + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/authentication_mfa_failed_context.json b/tests/Fixtures/authentication_mfa_failed_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/authentication_mfa_failed_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/authentication_mfa_failed_context_actor.json b/tests/Fixtures/authentication_mfa_failed_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/authentication_mfa_failed_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/authentication_mfa_failed_context_google_analytics_session.json b/tests/Fixtures/authentication_mfa_failed_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/authentication_mfa_failed_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/authentication_mfa_failed_data.json b/tests/Fixtures/authentication_mfa_failed_data.json new file mode 100644 index 00000000..ed6732f8 --- /dev/null +++ b/tests/Fixtures/authentication_mfa_failed_data.json @@ -0,0 +1,12 @@ +{ + "type": "mfa", + "status": "failed", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com", + "error": { + "code": "mfa_challenge_failed", + "message": "The MFA challenge has failed." + } +} diff --git a/tests/Fixtures/authentication_mfa_failed_data_error.json b/tests/Fixtures/authentication_mfa_failed_data_error.json new file mode 100644 index 00000000..8729bbbf --- /dev/null +++ b/tests/Fixtures/authentication_mfa_failed_data_error.json @@ -0,0 +1,4 @@ +{ + "code": "mfa_challenge_failed", + "message": "The MFA challenge has failed." +} diff --git a/tests/Fixtures/authentication_mfa_succeeded.json b/tests/Fixtures/authentication_mfa_succeeded.json new file mode 100644 index 00000000..ed151de8 --- /dev/null +++ b/tests/Fixtures/authentication_mfa_succeeded.json @@ -0,0 +1,34 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "authentication.mfa_succeeded", + "data": { + "type": "mfa", + "status": "succeeded", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/authentication_mfa_succeeded_context.json b/tests/Fixtures/authentication_mfa_succeeded_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/authentication_mfa_succeeded_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/authentication_mfa_succeeded_context_actor.json b/tests/Fixtures/authentication_mfa_succeeded_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/authentication_mfa_succeeded_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/authentication_mfa_succeeded_context_google_analytics_session.json b/tests/Fixtures/authentication_mfa_succeeded_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/authentication_mfa_succeeded_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/authentication_mfa_succeeded_data.json b/tests/Fixtures/authentication_mfa_succeeded_data.json new file mode 100644 index 00000000..1fc4705e --- /dev/null +++ b/tests/Fixtures/authentication_mfa_succeeded_data.json @@ -0,0 +1,8 @@ +{ + "type": "mfa", + "status": "succeeded", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com" +} diff --git a/tests/Fixtures/authentication_oauth_failed.json b/tests/Fixtures/authentication_oauth_failed.json new file mode 100644 index 00000000..b2aa1291 --- /dev/null +++ b/tests/Fixtures/authentication_oauth_failed.json @@ -0,0 +1,38 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "authentication.oauth_failed", + "data": { + "type": "oauth", + "status": "failed", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com", + "error": { + "code": "mfa_challenge_failed", + "message": "The MFA challenge has failed." + } + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/authentication_oauth_failed_context.json b/tests/Fixtures/authentication_oauth_failed_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/authentication_oauth_failed_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/authentication_oauth_failed_context_actor.json b/tests/Fixtures/authentication_oauth_failed_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/authentication_oauth_failed_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/authentication_oauth_failed_context_google_analytics_session.json b/tests/Fixtures/authentication_oauth_failed_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/authentication_oauth_failed_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/authentication_oauth_failed_data.json b/tests/Fixtures/authentication_oauth_failed_data.json new file mode 100644 index 00000000..46d3a614 --- /dev/null +++ b/tests/Fixtures/authentication_oauth_failed_data.json @@ -0,0 +1,12 @@ +{ + "type": "oauth", + "status": "failed", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com", + "error": { + "code": "mfa_challenge_failed", + "message": "The MFA challenge has failed." + } +} diff --git a/tests/Fixtures/authentication_oauth_failed_data_error.json b/tests/Fixtures/authentication_oauth_failed_data_error.json new file mode 100644 index 00000000..8729bbbf --- /dev/null +++ b/tests/Fixtures/authentication_oauth_failed_data_error.json @@ -0,0 +1,4 @@ +{ + "code": "mfa_challenge_failed", + "message": "The MFA challenge has failed." +} diff --git a/tests/Fixtures/authentication_oauth_succeeded.json b/tests/Fixtures/authentication_oauth_succeeded.json new file mode 100644 index 00000000..8b69d6e4 --- /dev/null +++ b/tests/Fixtures/authentication_oauth_succeeded.json @@ -0,0 +1,34 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "authentication.oauth_succeeded", + "data": { + "type": "oauth", + "status": "succeeded", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/authentication_oauth_succeeded_context.json b/tests/Fixtures/authentication_oauth_succeeded_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/authentication_oauth_succeeded_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/authentication_oauth_succeeded_context_actor.json b/tests/Fixtures/authentication_oauth_succeeded_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/authentication_oauth_succeeded_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/authentication_oauth_succeeded_context_google_analytics_session.json b/tests/Fixtures/authentication_oauth_succeeded_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/authentication_oauth_succeeded_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/authentication_oauth_succeeded_data.json b/tests/Fixtures/authentication_oauth_succeeded_data.json new file mode 100644 index 00000000..437beddd --- /dev/null +++ b/tests/Fixtures/authentication_oauth_succeeded_data.json @@ -0,0 +1,8 @@ +{ + "type": "oauth", + "status": "succeeded", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com" +} diff --git a/tests/Fixtures/authentication_passkey_failed.json b/tests/Fixtures/authentication_passkey_failed.json new file mode 100644 index 00000000..26dd3e3d --- /dev/null +++ b/tests/Fixtures/authentication_passkey_failed.json @@ -0,0 +1,38 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "authentication.passkey_failed", + "data": { + "type": "passkey", + "status": "failed", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com", + "error": { + "code": "mfa_challenge_failed", + "message": "The MFA challenge has failed." + } + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/authentication_passkey_failed_context.json b/tests/Fixtures/authentication_passkey_failed_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/authentication_passkey_failed_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/authentication_passkey_failed_context_actor.json b/tests/Fixtures/authentication_passkey_failed_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/authentication_passkey_failed_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/authentication_passkey_failed_context_google_analytics_session.json b/tests/Fixtures/authentication_passkey_failed_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/authentication_passkey_failed_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/authentication_passkey_failed_data.json b/tests/Fixtures/authentication_passkey_failed_data.json new file mode 100644 index 00000000..071fd18d --- /dev/null +++ b/tests/Fixtures/authentication_passkey_failed_data.json @@ -0,0 +1,12 @@ +{ + "type": "passkey", + "status": "failed", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com", + "error": { + "code": "mfa_challenge_failed", + "message": "The MFA challenge has failed." + } +} diff --git a/tests/Fixtures/authentication_passkey_failed_data_error.json b/tests/Fixtures/authentication_passkey_failed_data_error.json new file mode 100644 index 00000000..8729bbbf --- /dev/null +++ b/tests/Fixtures/authentication_passkey_failed_data_error.json @@ -0,0 +1,4 @@ +{ + "code": "mfa_challenge_failed", + "message": "The MFA challenge has failed." +} diff --git a/tests/Fixtures/authentication_passkey_succeeded.json b/tests/Fixtures/authentication_passkey_succeeded.json new file mode 100644 index 00000000..d9ad38f8 --- /dev/null +++ b/tests/Fixtures/authentication_passkey_succeeded.json @@ -0,0 +1,34 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "authentication.passkey_succeeded", + "data": { + "type": "passkey", + "status": "succeeded", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/authentication_passkey_succeeded_context.json b/tests/Fixtures/authentication_passkey_succeeded_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/authentication_passkey_succeeded_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/authentication_passkey_succeeded_context_actor.json b/tests/Fixtures/authentication_passkey_succeeded_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/authentication_passkey_succeeded_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/authentication_passkey_succeeded_context_google_analytics_session.json b/tests/Fixtures/authentication_passkey_succeeded_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/authentication_passkey_succeeded_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/authentication_passkey_succeeded_data.json b/tests/Fixtures/authentication_passkey_succeeded_data.json new file mode 100644 index 00000000..51312920 --- /dev/null +++ b/tests/Fixtures/authentication_passkey_succeeded_data.json @@ -0,0 +1,8 @@ +{ + "type": "passkey", + "status": "succeeded", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com" +} diff --git a/tests/Fixtures/authentication_password_failed.json b/tests/Fixtures/authentication_password_failed.json new file mode 100644 index 00000000..9904b2a0 --- /dev/null +++ b/tests/Fixtures/authentication_password_failed.json @@ -0,0 +1,38 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "authentication.password_failed", + "data": { + "type": "password", + "status": "failed", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com", + "error": { + "code": "mfa_challenge_failed", + "message": "The MFA challenge has failed." + } + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/authentication_password_failed_context.json b/tests/Fixtures/authentication_password_failed_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/authentication_password_failed_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/authentication_password_failed_context_actor.json b/tests/Fixtures/authentication_password_failed_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/authentication_password_failed_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/authentication_password_failed_context_google_analytics_session.json b/tests/Fixtures/authentication_password_failed_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/authentication_password_failed_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/authentication_password_failed_data.json b/tests/Fixtures/authentication_password_failed_data.json new file mode 100644 index 00000000..f2abf729 --- /dev/null +++ b/tests/Fixtures/authentication_password_failed_data.json @@ -0,0 +1,12 @@ +{ + "type": "password", + "status": "failed", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com", + "error": { + "code": "mfa_challenge_failed", + "message": "The MFA challenge has failed." + } +} diff --git a/tests/Fixtures/authentication_password_failed_data_error.json b/tests/Fixtures/authentication_password_failed_data_error.json new file mode 100644 index 00000000..8729bbbf --- /dev/null +++ b/tests/Fixtures/authentication_password_failed_data_error.json @@ -0,0 +1,4 @@ +{ + "code": "mfa_challenge_failed", + "message": "The MFA challenge has failed." +} diff --git a/tests/Fixtures/authentication_password_succeeded.json b/tests/Fixtures/authentication_password_succeeded.json new file mode 100644 index 00000000..f4b02f54 --- /dev/null +++ b/tests/Fixtures/authentication_password_succeeded.json @@ -0,0 +1,34 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "authentication.password_succeeded", + "data": { + "type": "password", + "status": "succeeded", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/authentication_password_succeeded_context.json b/tests/Fixtures/authentication_password_succeeded_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/authentication_password_succeeded_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/authentication_password_succeeded_context_actor.json b/tests/Fixtures/authentication_password_succeeded_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/authentication_password_succeeded_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/authentication_password_succeeded_context_google_analytics_session.json b/tests/Fixtures/authentication_password_succeeded_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/authentication_password_succeeded_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/authentication_password_succeeded_data.json b/tests/Fixtures/authentication_password_succeeded_data.json new file mode 100644 index 00000000..9cc9e577 --- /dev/null +++ b/tests/Fixtures/authentication_password_succeeded_data.json @@ -0,0 +1,8 @@ +{ + "type": "password", + "status": "succeeded", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com" +} diff --git a/tests/Fixtures/authentication_radar_risk_detected.json b/tests/Fixtures/authentication_radar_risk_detected.json new file mode 100644 index 00000000..52ebf529 --- /dev/null +++ b/tests/Fixtures/authentication_radar_risk_detected.json @@ -0,0 +1,36 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "authentication.radar_risk_detected", + "data": { + "auth_method": "password", + "action": "signup", + "control": "block", + "blocklist_type": "ip", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/authentication_radar_risk_detected_context.json b/tests/Fixtures/authentication_radar_risk_detected_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/authentication_radar_risk_detected_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/authentication_radar_risk_detected_context_actor.json b/tests/Fixtures/authentication_radar_risk_detected_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/authentication_radar_risk_detected_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/authentication_radar_risk_detected_context_google_analytics_session.json b/tests/Fixtures/authentication_radar_risk_detected_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/authentication_radar_risk_detected_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/authentication_radar_risk_detected_data.json b/tests/Fixtures/authentication_radar_risk_detected_data.json new file mode 100644 index 00000000..7210f9e5 --- /dev/null +++ b/tests/Fixtures/authentication_radar_risk_detected_data.json @@ -0,0 +1,10 @@ +{ + "auth_method": "password", + "action": "signup", + "control": "block", + "blocklist_type": "ip", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com" +} diff --git a/tests/Fixtures/authentication_sso_failed.json b/tests/Fixtures/authentication_sso_failed.json new file mode 100644 index 00000000..f5ff78cd --- /dev/null +++ b/tests/Fixtures/authentication_sso_failed.json @@ -0,0 +1,43 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "authentication.sso_failed", + "data": { + "type": "sso", + "status": "failed", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com", + "sso": { + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "connection_id": "conn_01E4ZCR3C56J083X43JQXF3JK5", + "session_id": "sess_01E4ZCR3C56J083X43JQXF3JK5" + }, + "error": { + "code": "mfa_challenge_failed", + "message": "The MFA challenge has failed." + } + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/authentication_sso_failed_context.json b/tests/Fixtures/authentication_sso_failed_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/authentication_sso_failed_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/authentication_sso_failed_context_actor.json b/tests/Fixtures/authentication_sso_failed_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/authentication_sso_failed_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/authentication_sso_failed_context_google_analytics_session.json b/tests/Fixtures/authentication_sso_failed_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/authentication_sso_failed_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/authentication_sso_failed_data.json b/tests/Fixtures/authentication_sso_failed_data.json new file mode 100644 index 00000000..d7d10d34 --- /dev/null +++ b/tests/Fixtures/authentication_sso_failed_data.json @@ -0,0 +1,17 @@ +{ + "type": "sso", + "status": "failed", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com", + "sso": { + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "connection_id": "conn_01E4ZCR3C56J083X43JQXF3JK5", + "session_id": "sess_01E4ZCR3C56J083X43JQXF3JK5" + }, + "error": { + "code": "mfa_challenge_failed", + "message": "The MFA challenge has failed." + } +} diff --git a/tests/Fixtures/authentication_sso_failed_data_error.json b/tests/Fixtures/authentication_sso_failed_data_error.json new file mode 100644 index 00000000..8729bbbf --- /dev/null +++ b/tests/Fixtures/authentication_sso_failed_data_error.json @@ -0,0 +1,4 @@ +{ + "code": "mfa_challenge_failed", + "message": "The MFA challenge has failed." +} diff --git a/tests/Fixtures/authentication_sso_failed_data_sso.json b/tests/Fixtures/authentication_sso_failed_data_sso.json new file mode 100644 index 00000000..3ff1dd7d --- /dev/null +++ b/tests/Fixtures/authentication_sso_failed_data_sso.json @@ -0,0 +1,5 @@ +{ + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "connection_id": "conn_01E4ZCR3C56J083X43JQXF3JK5", + "session_id": "sess_01E4ZCR3C56J083X43JQXF3JK5" +} diff --git a/tests/Fixtures/authentication_sso_started.json b/tests/Fixtures/authentication_sso_started.json new file mode 100644 index 00000000..2dd8bb81 --- /dev/null +++ b/tests/Fixtures/authentication_sso_started.json @@ -0,0 +1,39 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "authentication.sso_started", + "data": { + "type": "sso", + "status": "started", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com", + "sso": { + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "connection_id": "conn_01E4ZCR3C56J083X43JQXF3JK5", + "session_id": "sess_01E4ZCR3C56J083X43JQXF3JK5" + } + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/authentication_sso_started_context.json b/tests/Fixtures/authentication_sso_started_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/authentication_sso_started_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/authentication_sso_started_context_actor.json b/tests/Fixtures/authentication_sso_started_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/authentication_sso_started_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/authentication_sso_started_context_google_analytics_session.json b/tests/Fixtures/authentication_sso_started_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/authentication_sso_started_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/authentication_sso_started_data.json b/tests/Fixtures/authentication_sso_started_data.json new file mode 100644 index 00000000..fc80feab --- /dev/null +++ b/tests/Fixtures/authentication_sso_started_data.json @@ -0,0 +1,13 @@ +{ + "type": "sso", + "status": "started", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com", + "sso": { + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "connection_id": "conn_01E4ZCR3C56J083X43JQXF3JK5", + "session_id": "sess_01E4ZCR3C56J083X43JQXF3JK5" + } +} diff --git a/tests/Fixtures/authentication_sso_started_data_sso.json b/tests/Fixtures/authentication_sso_started_data_sso.json new file mode 100644 index 00000000..3ff1dd7d --- /dev/null +++ b/tests/Fixtures/authentication_sso_started_data_sso.json @@ -0,0 +1,5 @@ +{ + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "connection_id": "conn_01E4ZCR3C56J083X43JQXF3JK5", + "session_id": "sess_01E4ZCR3C56J083X43JQXF3JK5" +} diff --git a/tests/Fixtures/authentication_sso_succeeded.json b/tests/Fixtures/authentication_sso_succeeded.json new file mode 100644 index 00000000..f467dbce --- /dev/null +++ b/tests/Fixtures/authentication_sso_succeeded.json @@ -0,0 +1,39 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "authentication.sso_succeeded", + "data": { + "type": "sso", + "status": "succeeded", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com", + "sso": { + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "connection_id": "conn_01E4ZCR3C56J083X43JQXF3JK5", + "session_id": "sess_01E4ZCR3C56J083X43JQXF3JK5" + } + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/authentication_sso_succeeded_context.json b/tests/Fixtures/authentication_sso_succeeded_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/authentication_sso_succeeded_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/authentication_sso_succeeded_context_actor.json b/tests/Fixtures/authentication_sso_succeeded_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/authentication_sso_succeeded_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/authentication_sso_succeeded_context_google_analytics_session.json b/tests/Fixtures/authentication_sso_succeeded_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/authentication_sso_succeeded_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/authentication_sso_succeeded_data.json b/tests/Fixtures/authentication_sso_succeeded_data.json new file mode 100644 index 00000000..1308f766 --- /dev/null +++ b/tests/Fixtures/authentication_sso_succeeded_data.json @@ -0,0 +1,13 @@ +{ + "type": "sso", + "status": "succeeded", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com", + "sso": { + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "connection_id": "conn_01E4ZCR3C56J083X43JQXF3JK5", + "session_id": "sess_01E4ZCR3C56J083X43JQXF3JK5" + } +} diff --git a/tests/Fixtures/authentication_sso_succeeded_data_sso.json b/tests/Fixtures/authentication_sso_succeeded_data_sso.json new file mode 100644 index 00000000..3ff1dd7d --- /dev/null +++ b/tests/Fixtures/authentication_sso_succeeded_data_sso.json @@ -0,0 +1,5 @@ +{ + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "connection_id": "conn_01E4ZCR3C56J083X43JQXF3JK5", + "session_id": "sess_01E4ZCR3C56J083X43JQXF3JK5" +} diff --git a/tests/Fixtures/authentication_sso_timed_out.json b/tests/Fixtures/authentication_sso_timed_out.json new file mode 100644 index 00000000..f4d9061a --- /dev/null +++ b/tests/Fixtures/authentication_sso_timed_out.json @@ -0,0 +1,43 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "authentication.sso_timed_out", + "data": { + "type": "sso", + "status": "timed_out", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com", + "sso": { + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "connection_id": "conn_01E4ZCR3C56J083X43JQXF3JK5", + "session_id": "sess_01E4ZCR3C56J083X43JQXF3JK5" + }, + "error": { + "code": "mfa_challenge_failed", + "message": "The MFA challenge has failed." + } + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/authentication_sso_timed_out_context.json b/tests/Fixtures/authentication_sso_timed_out_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/authentication_sso_timed_out_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/authentication_sso_timed_out_context_actor.json b/tests/Fixtures/authentication_sso_timed_out_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/authentication_sso_timed_out_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/authentication_sso_timed_out_context_google_analytics_session.json b/tests/Fixtures/authentication_sso_timed_out_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/authentication_sso_timed_out_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/authentication_sso_timed_out_data.json b/tests/Fixtures/authentication_sso_timed_out_data.json new file mode 100644 index 00000000..4f6fe32f --- /dev/null +++ b/tests/Fixtures/authentication_sso_timed_out_data.json @@ -0,0 +1,17 @@ +{ + "type": "sso", + "status": "timed_out", + "ip_address": "203.0.113.42", + "user_agent": "Mozilla/5.0", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "user@example.com", + "sso": { + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "connection_id": "conn_01E4ZCR3C56J083X43JQXF3JK5", + "session_id": "sess_01E4ZCR3C56J083X43JQXF3JK5" + }, + "error": { + "code": "mfa_challenge_failed", + "message": "The MFA challenge has failed." + } +} diff --git a/tests/Fixtures/authentication_sso_timed_out_data_error.json b/tests/Fixtures/authentication_sso_timed_out_data_error.json new file mode 100644 index 00000000..8729bbbf --- /dev/null +++ b/tests/Fixtures/authentication_sso_timed_out_data_error.json @@ -0,0 +1,4 @@ +{ + "code": "mfa_challenge_failed", + "message": "The MFA challenge has failed." +} diff --git a/tests/Fixtures/authentication_sso_timed_out_data_sso.json b/tests/Fixtures/authentication_sso_timed_out_data_sso.json new file mode 100644 index 00000000..3ff1dd7d --- /dev/null +++ b/tests/Fixtures/authentication_sso_timed_out_data_sso.json @@ -0,0 +1,5 @@ +{ + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "connection_id": "conn_01E4ZCR3C56J083X43JQXF3JK5", + "session_id": "sess_01E4ZCR3C56J083X43JQXF3JK5" +} diff --git a/tests/Fixtures/authorization_check.json b/tests/Fixtures/authorization_check.json new file mode 100644 index 00000000..8a5f5f97 --- /dev/null +++ b/tests/Fixtures/authorization_check.json @@ -0,0 +1,3 @@ +{ + "authorized": true +} diff --git a/tests/Fixtures/authorization_code_session_authenticate_request.json b/tests/Fixtures/authorization_code_session_authenticate_request.json new file mode 100644 index 00000000..a68dbe87 --- /dev/null +++ b/tests/Fixtures/authorization_code_session_authenticate_request.json @@ -0,0 +1,9 @@ +{ + "client_id": "client_01HXYZ123456789ABCDEFGHIJ", + "client_secret": "sk_test_....", + "grant_type": "authorization_code", + "code": "vBqZKaPpsnJlPfXiDqN7b6VTz", + "ip_address": "203.0.113.42", + "device_id": "device_01HXYZ123456789ABCDEFGHIJ", + "user_agent": "Mozilla/5.0" +} diff --git a/tests/Fixtures/authorization_permission.json b/tests/Fixtures/authorization_permission.json new file mode 100644 index 00000000..0424eed6 --- /dev/null +++ b/tests/Fixtures/authorization_permission.json @@ -0,0 +1,11 @@ +{ + "object": "permission", + "id": "perm_01HXYZ123456789ABCDEFGHIJ", + "slug": "documents:read", + "name": "View Documents", + "description": "Allows viewing document contents", + "system": false, + "resource_type_slug": "workspace", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/authorization_permission_list_list_metadata.json b/tests/Fixtures/authorization_permission_list_list_metadata.json new file mode 100644 index 00000000..65138cca --- /dev/null +++ b/tests/Fixtures/authorization_permission_list_list_metadata.json @@ -0,0 +1,4 @@ +{ + "before": "perm_01HXYZ123456789ABCDEFGHIJ", + "after": "perm_01HXYZ987654321KJIHGFEDCBA" +} diff --git a/tests/Fixtures/authorization_resource.json b/tests/Fixtures/authorization_resource.json new file mode 100644 index 00000000..ee5271ee --- /dev/null +++ b/tests/Fixtures/authorization_resource.json @@ -0,0 +1,12 @@ +{ + "object": "authorization_resource", + "name": "Website Redesign", + "description": "Company website redesign project", + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", + "parent_resource_id": "authz_resource_01HXYZ123456789ABCDEFGHIJ", + "id": "authz_resource_01HXYZ123456789ABCDEFGH", + "external_id": "proj-456", + "resource_type_slug": "project", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/authorization_resource_list_list_metadata.json b/tests/Fixtures/authorization_resource_list_list_metadata.json new file mode 100644 index 00000000..0e38a4d8 --- /dev/null +++ b/tests/Fixtures/authorization_resource_list_list_metadata.json @@ -0,0 +1,4 @@ +{ + "before": "authz_resource_01HXYZ123456789ABCDEFGHIJ", + "after": "authz_resource_01HXYZ987654321KJIHGFEDCBA" +} diff --git a/tests/Fixtures/authorized_connect_application_list_data.json b/tests/Fixtures/authorized_connect_application_list_data.json new file mode 100644 index 00000000..bd3d6a14 --- /dev/null +++ b/tests/Fixtures/authorized_connect_application_list_data.json @@ -0,0 +1,23 @@ +{ + "object": "authorized_connect_application", + "id": "authorized_connect_app_01HXYZ123456789ABCDEFGHIJ", + "granted_scopes": [ + "openid", + "profile", + "email" + ], + "application": { + "object": "connect_application", + "id": "conn_app_01HXYZ123456789ABCDEFGHIJ", + "client_id": "client_01HXYZ123456789ABCDEFGHIJ", + "description": "An application for managing user access", + "name": "My Application", + "scopes": [ + "openid", + "profile", + "email" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } +} diff --git a/tests/Fixtures/authorized_connect_application_list_list_metadata.json b/tests/Fixtures/authorized_connect_application_list_list_metadata.json new file mode 100644 index 00000000..803cae45 --- /dev/null +++ b/tests/Fixtures/authorized_connect_application_list_list_metadata.json @@ -0,0 +1,4 @@ +{ + "before": "authorized_connect_app_01HXYZ123456789ABCDEFGHIJ", + "after": "authorized_connect_app_01HXYZ987654321KJIHGFEDCBA" +} diff --git a/tests/Fixtures/challenge_authentication_factor.json b/tests/Fixtures/challenge_authentication_factor.json new file mode 100644 index 00000000..07c623af --- /dev/null +++ b/tests/Fixtures/challenge_authentication_factor.json @@ -0,0 +1,3 @@ +{ + "sms_template": "Your verification code is {{code}}." +} diff --git a/tests/Fixtures/check_authorization.json b/tests/Fixtures/check_authorization.json new file mode 100644 index 00000000..ed8ae94e --- /dev/null +++ b/tests/Fixtures/check_authorization.json @@ -0,0 +1,6 @@ +{ + "permission_slug": "posts:create", + "resource_id": "resource_01HXYZ123456789ABCDEFGHIJ", + "resource_external_id": "my-custom-id", + "resource_type_slug": "document" +} diff --git a/tests/Fixtures/confirm_email_change.json b/tests/Fixtures/confirm_email_change.json new file mode 100644 index 00000000..736bf40a --- /dev/null +++ b/tests/Fixtures/confirm_email_change.json @@ -0,0 +1,3 @@ +{ + "code": "123456" +} diff --git a/tests/Fixtures/connect_application.json b/tests/Fixtures/connect_application.json new file mode 100644 index 00000000..94258b88 --- /dev/null +++ b/tests/Fixtures/connect_application.json @@ -0,0 +1,14 @@ +{ + "object": "connect_application", + "id": "conn_app_01HXYZ123456789ABCDEFGHIJ", + "client_id": "client_01HXYZ123456789ABCDEFGHIJ", + "description": "An application for managing user access", + "name": "My Application", + "scopes": [ + "openid", + "profile", + "email" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/connect_application_list_list_metadata.json b/tests/Fixtures/connect_application_list_list_metadata.json new file mode 100644 index 00000000..9f6dd098 --- /dev/null +++ b/tests/Fixtures/connect_application_list_list_metadata.json @@ -0,0 +1,4 @@ +{ + "before": "conn_app_01HXYZ123456789ABCDEFGHIJ", + "after": "conn_app_01HXYZ987654321KJIHGFEDCBA" +} diff --git a/tests/Fixtures/connected_account.json b/tests/Fixtures/connected_account.json new file mode 100644 index 00000000..ffc4db77 --- /dev/null +++ b/tests/Fixtures/connected_account.json @@ -0,0 +1,13 @@ +{ + "object": "connected_account", + "id": "data_installation_01EHZNVPK3SFK441A1RGBFSHRT", + "user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT", + "organization_id": null, + "scopes": [ + "repo", + "user:email" + ], + "state": "connected", + "created_at": "2024-01-16T14:20:00.000Z", + "updated_at": "2024-01-16T14:20:00.000Z" +} diff --git a/tests/Fixtures/connection.json b/tests/Fixtures/connection.json new file mode 100644 index 00000000..2caf9273 --- /dev/null +++ b/tests/Fixtures/connection.json @@ -0,0 +1,21 @@ +{ + "object": "connection", + "id": "conn_01E4ZCR3C56J083X43JQXF3JK5", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "connection_type": "OktaSAML", + "name": "Foo Corp", + "state": "active", + "status": "linked", + "domains": [ + { + "id": "org_domain_01EHZNVPK2QXHMVWCEDQEKY69A", + "object": "connection_domain", + "domain": "foo-corp.com" + } + ], + "options": { + "signing_cert": null + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/connection_activated.json b/tests/Fixtures/connection_activated.json new file mode 100644 index 00000000..e83a62a5 --- /dev/null +++ b/tests/Fixtures/connection_activated.json @@ -0,0 +1,45 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "connection.activated", + "data": { + "object": "connection", + "id": "conn_01EHWNCE74X7JSDV0X3SZ3KJNY", + "state": "active", + "name": "Acme SSO", + "connection_type": "OktaSAML", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "external_key": "ext_01EHWNCE74X7JSDV0X3SZ3KJNY", + "status": "linked", + "domains": [ + { + "object": "connection_domain", + "id": "conn_domain_01EHWNCE74X7JSDV0X3SZ3KJNY", + "domain": "acme.com" + } + ] + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/connection_activated_context.json b/tests/Fixtures/connection_activated_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/connection_activated_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/connection_activated_context_actor.json b/tests/Fixtures/connection_activated_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/connection_activated_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/connection_activated_context_google_analytics_session.json b/tests/Fixtures/connection_activated_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/connection_activated_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/connection_activated_data.json b/tests/Fixtures/connection_activated_data.json new file mode 100644 index 00000000..ed428010 --- /dev/null +++ b/tests/Fixtures/connection_activated_data.json @@ -0,0 +1,19 @@ +{ + "object": "connection", + "id": "conn_01EHWNCE74X7JSDV0X3SZ3KJNY", + "state": "active", + "name": "Acme SSO", + "connection_type": "OktaSAML", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "external_key": "ext_01EHWNCE74X7JSDV0X3SZ3KJNY", + "status": "linked", + "domains": [ + { + "object": "connection_domain", + "id": "conn_domain_01EHWNCE74X7JSDV0X3SZ3KJNY", + "domain": "acme.com" + } + ] +} diff --git a/tests/Fixtures/connection_activated_data_domain.json b/tests/Fixtures/connection_activated_data_domain.json new file mode 100644 index 00000000..c60c2fe4 --- /dev/null +++ b/tests/Fixtures/connection_activated_data_domain.json @@ -0,0 +1,5 @@ +{ + "object": "connection_domain", + "id": "conn_domain_01EHWNCE74X7JSDV0X3SZ3KJNY", + "domain": "acme.com" +} diff --git a/tests/Fixtures/connection_deactivated.json b/tests/Fixtures/connection_deactivated.json new file mode 100644 index 00000000..0636e74c --- /dev/null +++ b/tests/Fixtures/connection_deactivated.json @@ -0,0 +1,45 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "connection.deactivated", + "data": { + "object": "connection", + "id": "conn_01EHWNCE74X7JSDV0X3SZ3KJNY", + "state": "active", + "name": "Acme SSO", + "connection_type": "OktaSAML", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "external_key": "ext_01EHWNCE74X7JSDV0X3SZ3KJNY", + "status": "linked", + "domains": [ + { + "object": "connection_domain", + "id": "conn_domain_01EHWNCE74X7JSDV0X3SZ3KJNY", + "domain": "acme.com" + } + ] + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/connection_deactivated_context.json b/tests/Fixtures/connection_deactivated_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/connection_deactivated_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/connection_deactivated_context_actor.json b/tests/Fixtures/connection_deactivated_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/connection_deactivated_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/connection_deactivated_context_google_analytics_session.json b/tests/Fixtures/connection_deactivated_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/connection_deactivated_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/connection_deactivated_data.json b/tests/Fixtures/connection_deactivated_data.json new file mode 100644 index 00000000..ed428010 --- /dev/null +++ b/tests/Fixtures/connection_deactivated_data.json @@ -0,0 +1,19 @@ +{ + "object": "connection", + "id": "conn_01EHWNCE74X7JSDV0X3SZ3KJNY", + "state": "active", + "name": "Acme SSO", + "connection_type": "OktaSAML", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "external_key": "ext_01EHWNCE74X7JSDV0X3SZ3KJNY", + "status": "linked", + "domains": [ + { + "object": "connection_domain", + "id": "conn_domain_01EHWNCE74X7JSDV0X3SZ3KJNY", + "domain": "acme.com" + } + ] +} diff --git a/tests/Fixtures/connection_deactivated_data_domain.json b/tests/Fixtures/connection_deactivated_data_domain.json new file mode 100644 index 00000000..c60c2fe4 --- /dev/null +++ b/tests/Fixtures/connection_deactivated_data_domain.json @@ -0,0 +1,5 @@ +{ + "object": "connection_domain", + "id": "conn_domain_01EHWNCE74X7JSDV0X3SZ3KJNY", + "domain": "acme.com" +} diff --git a/tests/Fixtures/connection_deleted.json b/tests/Fixtures/connection_deleted.json new file mode 100644 index 00000000..104f9d58 --- /dev/null +++ b/tests/Fixtures/connection_deleted.json @@ -0,0 +1,36 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "connection.deleted", + "data": { + "object": "connection", + "id": "conn_01EHWNCE74X7JSDV0X3SZ3KJNY", + "state": "active", + "name": "Acme SSO", + "connection_type": "OktaSAML", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/connection_deleted_context.json b/tests/Fixtures/connection_deleted_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/connection_deleted_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/connection_deleted_context_actor.json b/tests/Fixtures/connection_deleted_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/connection_deleted_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/connection_deleted_context_google_analytics_session.json b/tests/Fixtures/connection_deleted_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/connection_deleted_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/connection_deleted_data.json b/tests/Fixtures/connection_deleted_data.json new file mode 100644 index 00000000..0f35b1d8 --- /dev/null +++ b/tests/Fixtures/connection_deleted_data.json @@ -0,0 +1,10 @@ +{ + "object": "connection", + "id": "conn_01EHWNCE74X7JSDV0X3SZ3KJNY", + "state": "active", + "name": "Acme SSO", + "connection_type": "OktaSAML", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/connection_domain.json b/tests/Fixtures/connection_domain.json new file mode 100644 index 00000000..83396c2b --- /dev/null +++ b/tests/Fixtures/connection_domain.json @@ -0,0 +1,5 @@ +{ + "id": "org_domain_01EHZNVPK2QXHMVWCEDQEKY69A", + "object": "connection_domain", + "domain": "foo-corp.com" +} diff --git a/tests/Fixtures/connection_list_list_metadata.json b/tests/Fixtures/connection_list_list_metadata.json new file mode 100644 index 00000000..0ee5f6ed --- /dev/null +++ b/tests/Fixtures/connection_list_list_metadata.json @@ -0,0 +1,4 @@ +{ + "before": "conn_01HXYZ123456789ABCDEFGHIJ", + "after": "conn_01HXYZ987654321KJIHGFEDCBA" +} diff --git a/tests/Fixtures/connection_option.json b/tests/Fixtures/connection_option.json new file mode 100644 index 00000000..3912dcb4 --- /dev/null +++ b/tests/Fixtures/connection_option.json @@ -0,0 +1,3 @@ +{ + "signing_cert": null +} diff --git a/tests/Fixtures/connection_saml_certificate_renewal_required.json b/tests/Fixtures/connection_saml_certificate_renewal_required.json new file mode 100644 index 00000000..30ed8794 --- /dev/null +++ b/tests/Fixtures/connection_saml_certificate_renewal_required.json @@ -0,0 +1,38 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "connection.saml_certificate_renewal_required", + "data": { + "connection": { + "id": "conn_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY" + }, + "certificate": { + "certificate_type": "ResponseSigning", + "expiry_date": "2026-01-15T12:00:00.000Z", + "is_expired": false + }, + "days_until_expiry": 30 + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/connection_saml_certificate_renewal_required_context.json b/tests/Fixtures/connection_saml_certificate_renewal_required_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/connection_saml_certificate_renewal_required_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/connection_saml_certificate_renewal_required_context_actor.json b/tests/Fixtures/connection_saml_certificate_renewal_required_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/connection_saml_certificate_renewal_required_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/connection_saml_certificate_renewal_required_context_google_analytics_session.json b/tests/Fixtures/connection_saml_certificate_renewal_required_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/connection_saml_certificate_renewal_required_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/connection_saml_certificate_renewal_required_data.json b/tests/Fixtures/connection_saml_certificate_renewal_required_data.json new file mode 100644 index 00000000..1f836ea9 --- /dev/null +++ b/tests/Fixtures/connection_saml_certificate_renewal_required_data.json @@ -0,0 +1,12 @@ +{ + "connection": { + "id": "conn_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY" + }, + "certificate": { + "certificate_type": "ResponseSigning", + "expiry_date": "2026-01-15T12:00:00.000Z", + "is_expired": false + }, + "days_until_expiry": 30 +} diff --git a/tests/Fixtures/connection_saml_certificate_renewal_required_data_certificate.json b/tests/Fixtures/connection_saml_certificate_renewal_required_data_certificate.json new file mode 100644 index 00000000..c50223a5 --- /dev/null +++ b/tests/Fixtures/connection_saml_certificate_renewal_required_data_certificate.json @@ -0,0 +1,5 @@ +{ + "certificate_type": "ResponseSigning", + "expiry_date": "2026-01-15T12:00:00.000Z", + "is_expired": false +} diff --git a/tests/Fixtures/connection_saml_certificate_renewal_required_data_connection.json b/tests/Fixtures/connection_saml_certificate_renewal_required_data_connection.json new file mode 100644 index 00000000..2fe9b1af --- /dev/null +++ b/tests/Fixtures/connection_saml_certificate_renewal_required_data_connection.json @@ -0,0 +1,4 @@ +{ + "id": "conn_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY" +} diff --git a/tests/Fixtures/connection_saml_certificate_renewed.json b/tests/Fixtures/connection_saml_certificate_renewed.json new file mode 100644 index 00000000..eabcb9bc --- /dev/null +++ b/tests/Fixtures/connection_saml_certificate_renewed.json @@ -0,0 +1,37 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "connection.saml_certificate_renewed", + "data": { + "connection": { + "id": "conn_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY" + }, + "certificate": { + "certificate_type": "ResponseSigning", + "expiry_date": "2026-01-15T12:00:00.000Z" + }, + "renewed_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/connection_saml_certificate_renewed_context.json b/tests/Fixtures/connection_saml_certificate_renewed_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/connection_saml_certificate_renewed_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/connection_saml_certificate_renewed_context_actor.json b/tests/Fixtures/connection_saml_certificate_renewed_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/connection_saml_certificate_renewed_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/connection_saml_certificate_renewed_context_google_analytics_session.json b/tests/Fixtures/connection_saml_certificate_renewed_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/connection_saml_certificate_renewed_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/connection_saml_certificate_renewed_data.json b/tests/Fixtures/connection_saml_certificate_renewed_data.json new file mode 100644 index 00000000..3491ca99 --- /dev/null +++ b/tests/Fixtures/connection_saml_certificate_renewed_data.json @@ -0,0 +1,11 @@ +{ + "connection": { + "id": "conn_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY" + }, + "certificate": { + "certificate_type": "ResponseSigning", + "expiry_date": "2026-01-15T12:00:00.000Z" + }, + "renewed_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/connection_saml_certificate_renewed_data_certificate.json b/tests/Fixtures/connection_saml_certificate_renewed_data_certificate.json new file mode 100644 index 00000000..95776344 --- /dev/null +++ b/tests/Fixtures/connection_saml_certificate_renewed_data_certificate.json @@ -0,0 +1,4 @@ +{ + "certificate_type": "ResponseSigning", + "expiry_date": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/connection_saml_certificate_renewed_data_connection.json b/tests/Fixtures/connection_saml_certificate_renewed_data_connection.json new file mode 100644 index 00000000..2fe9b1af --- /dev/null +++ b/tests/Fixtures/connection_saml_certificate_renewed_data_connection.json @@ -0,0 +1,4 @@ +{ + "id": "conn_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY" +} diff --git a/tests/Fixtures/cors_origin_response.json b/tests/Fixtures/cors_origin_response.json new file mode 100644 index 00000000..c70c3b3c --- /dev/null +++ b/tests/Fixtures/cors_origin_response.json @@ -0,0 +1,7 @@ +{ + "object": "cors_origin", + "id": "cors_origin_01HXYZ123456789ABCDEFGHIJ", + "origin": "https://example.com", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/create_application_secret.json b/tests/Fixtures/create_application_secret.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/tests/Fixtures/create_application_secret.json @@ -0,0 +1 @@ +{} diff --git a/tests/Fixtures/create_authorization_permission.json b/tests/Fixtures/create_authorization_permission.json new file mode 100644 index 00000000..6c9dc2ae --- /dev/null +++ b/tests/Fixtures/create_authorization_permission.json @@ -0,0 +1,6 @@ +{ + "slug": "documents:read", + "name": "View Documents", + "description": "Allows viewing document contents", + "resource_type_slug": "document" +} diff --git a/tests/Fixtures/create_authorization_resource.json b/tests/Fixtures/create_authorization_resource.json new file mode 100644 index 00000000..04b09a07 --- /dev/null +++ b/tests/Fixtures/create_authorization_resource.json @@ -0,0 +1,10 @@ +{ + "external_id": "my-workspace-01", + "name": "Acme Workspace", + "description": "Primary workspace for the Acme team", + "resource_type_slug": "workspace", + "organization_id": "org_01EHQMYV6MBK39QC5PZXHY59C3", + "parent_resource_id": "authz_resource_01HXYZ123456789ABCDEFGHIJ", + "parent_resource_external_id": "parent-workspace-01", + "parent_resource_type_slug": "workspace" +} diff --git a/tests/Fixtures/create_cors_origin.json b/tests/Fixtures/create_cors_origin.json new file mode 100644 index 00000000..3b5477cf --- /dev/null +++ b/tests/Fixtures/create_cors_origin.json @@ -0,0 +1,3 @@ +{ + "origin": "https://example.com" +} diff --git a/tests/Fixtures/create_m2m_application.json b/tests/Fixtures/create_m2m_application.json new file mode 100644 index 00000000..ecfaf00d --- /dev/null +++ b/tests/Fixtures/create_m2m_application.json @@ -0,0 +1,11 @@ +{ + "name": "My Application", + "application_type": "m2m", + "description": "An application for managing user access", + "scopes": [ + "openid", + "profile", + "email" + ], + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT" +} diff --git a/tests/Fixtures/create_magic_code_and_return.json b/tests/Fixtures/create_magic_code_and_return.json new file mode 100644 index 00000000..10708580 --- /dev/null +++ b/tests/Fixtures/create_magic_code_and_return.json @@ -0,0 +1,4 @@ +{ + "email": "marcelina.davis@example.com", + "invitation_token": "Z1Y2X3W4V5U6T7S8R9Q0P1O2N3" +} diff --git a/tests/Fixtures/create_oauth_application.json b/tests/Fixtures/create_oauth_application.json new file mode 100644 index 00000000..343693c1 --- /dev/null +++ b/tests/Fixtures/create_oauth_application.json @@ -0,0 +1,19 @@ +{ + "name": "My Application", + "application_type": "oauth", + "description": "An application for managing user access", + "scopes": [ + "openid", + "profile", + "email" + ], + "redirect_uris": [ + { + "uri": "https://example.com/callback", + "default": true + } + ], + "uses_pkce": true, + "is_first_party": true, + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT" +} diff --git a/tests/Fixtures/create_organization_api_key.json b/tests/Fixtures/create_organization_api_key.json new file mode 100644 index 00000000..d2791c16 --- /dev/null +++ b/tests/Fixtures/create_organization_api_key.json @@ -0,0 +1,7 @@ +{ + "name": "Production API Key", + "permissions": [ + "posts:read", + "posts:write" + ] +} diff --git a/tests/Fixtures/create_organization_domain.json b/tests/Fixtures/create_organization_domain.json new file mode 100644 index 00000000..ce43a5f2 --- /dev/null +++ b/tests/Fixtures/create_organization_domain.json @@ -0,0 +1,4 @@ +{ + "domain": "foo-corp.com", + "organization_id": "org_01EHQMYV6MBK39QC5PZXHY59C3" +} diff --git a/tests/Fixtures/create_organization_role.json b/tests/Fixtures/create_organization_role.json new file mode 100644 index 00000000..794a619b --- /dev/null +++ b/tests/Fixtures/create_organization_role.json @@ -0,0 +1,6 @@ +{ + "slug": "org-billing-admin", + "name": "Billing Administrator", + "description": "Can manage billing and invoices", + "resource_type_slug": "organization" +} diff --git a/tests/Fixtures/create_password_reset.json b/tests/Fixtures/create_password_reset.json new file mode 100644 index 00000000..d66c0ce0 --- /dev/null +++ b/tests/Fixtures/create_password_reset.json @@ -0,0 +1,4 @@ +{ + "token": "Z1Y2X3W4V5U6T7S8R9Q0P1O2N3", + "new_password": "strong_password_123!" +} diff --git a/tests/Fixtures/create_password_reset_token.json b/tests/Fixtures/create_password_reset_token.json new file mode 100644 index 00000000..3cfe18e9 --- /dev/null +++ b/tests/Fixtures/create_password_reset_token.json @@ -0,0 +1,3 @@ +{ + "email": "marcelina.davis@example.com" +} diff --git a/tests/Fixtures/create_redirect_uri.json b/tests/Fixtures/create_redirect_uri.json new file mode 100644 index 00000000..47e55d10 --- /dev/null +++ b/tests/Fixtures/create_redirect_uri.json @@ -0,0 +1,3 @@ +{ + "uri": "https://example.com/callback" +} diff --git a/tests/Fixtures/create_role.json b/tests/Fixtures/create_role.json new file mode 100644 index 00000000..a455dd22 --- /dev/null +++ b/tests/Fixtures/create_role.json @@ -0,0 +1,6 @@ +{ + "slug": "editor", + "name": "Editor", + "description": "Can edit resources", + "resource_type_slug": "organization" +} diff --git a/tests/Fixtures/create_user.json b/tests/Fixtures/create_user.json new file mode 100644 index 00000000..d64790ef --- /dev/null +++ b/tests/Fixtures/create_user.json @@ -0,0 +1,13 @@ +{ + "email": "marcelina.davis@example.com", + "password": "strong_password_123!", + "password_hash": "$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy", + "password_hash_type": "bcrypt", + "first_name": "Marcelina", + "last_name": "Davis", + "email_verified": true, + "metadata": { + "timezone": "America/New_York" + }, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222" +} diff --git a/tests/Fixtures/create_user_invite_options.json b/tests/Fixtures/create_user_invite_options.json new file mode 100644 index 00000000..ba523b01 --- /dev/null +++ b/tests/Fixtures/create_user_invite_options.json @@ -0,0 +1,8 @@ +{ + "email": "marcelina.davis@example.com", + "organization_id": "org_01E4ZCR3C56J083X43JQXF3JK5", + "role_slug": "admin", + "expires_in_days": 7, + "inviter_user_id": "user_01HYGBX8ZGD19949T3BM4FW1C3", + "locale": "en" +} diff --git a/tests/Fixtures/create_user_organization_membership.json b/tests/Fixtures/create_user_organization_membership.json new file mode 100644 index 00000000..b79b024e --- /dev/null +++ b/tests/Fixtures/create_user_organization_membership.json @@ -0,0 +1,8 @@ +{ + "user_id": "user_01E4ZCR3C5A4QZ2Z2JQXGKZJ9E", + "organization_id": "org_01E4ZCR3C56J083X43JQXF3JK5", + "role_slug": "admin", + "role_slugs": [ + "admin" + ] +} diff --git a/tests/Fixtures/create_webhook_endpoint.json b/tests/Fixtures/create_webhook_endpoint.json new file mode 100644 index 00000000..c382a990 --- /dev/null +++ b/tests/Fixtures/create_webhook_endpoint.json @@ -0,0 +1,7 @@ +{ + "endpoint_url": "https://example.com/webhooks", + "events": [ + "user.created", + "dsync.user.created" + ] +} diff --git a/tests/Fixtures/data_integration_access_token_response.json b/tests/Fixtures/data_integration_access_token_response.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/tests/Fixtures/data_integration_access_token_response.json @@ -0,0 +1 @@ +{} diff --git a/tests/Fixtures/data_integration_authorize_url_response.json b/tests/Fixtures/data_integration_authorize_url_response.json new file mode 100644 index 00000000..0d6b120d --- /dev/null +++ b/tests/Fixtures/data_integration_authorize_url_response.json @@ -0,0 +1,3 @@ +{ + "url": "https://api.workos.com/data-integrations/q2czJKmVAraSBg8xFpT7M9uR/authorize-redirect" +} diff --git a/tests/Fixtures/data_integrations_get_data_integration_authorize_url_request.json b/tests/Fixtures/data_integrations_get_data_integration_authorize_url_request.json new file mode 100644 index 00000000..b38a7cd5 --- /dev/null +++ b/tests/Fixtures/data_integrations_get_data_integration_authorize_url_request.json @@ -0,0 +1,5 @@ +{ + "user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT", + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", + "return_to": "https://example.com/callback" +} diff --git a/tests/Fixtures/data_integrations_get_user_token_request.json b/tests/Fixtures/data_integrations_get_user_token_request.json new file mode 100644 index 00000000..ef8c4438 --- /dev/null +++ b/tests/Fixtures/data_integrations_get_user_token_request.json @@ -0,0 +1,4 @@ +{ + "user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT", + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT" +} diff --git a/tests/Fixtures/data_integrations_list_response.json b/tests/Fixtures/data_integrations_list_response.json new file mode 100644 index 00000000..f395c192 --- /dev/null +++ b/tests/Fixtures/data_integrations_list_response.json @@ -0,0 +1,42 @@ +{ + "object": "list", + "data": [ + { + "object": "data_provider", + "id": "data_integration_01EHZNVPK3SFK441A1RGBFSHRT", + "name": "GitHub", + "description": "Connect your GitHub account to access repositories.", + "slug": "github", + "integration_type": "github", + "credentials_type": "oauth2", + "scopes": [ + "repo", + "user:email" + ], + "ownership": "userland_user", + "created_at": "2024-01-15T10:30:00.000Z", + "updated_at": "2024-01-15T10:30:00.000Z", + "integrationType": "test_integrationType", + "credentialsType": "test_credentialsType", + "createdAt": "test_createdAt", + "updatedAt": "test_updatedAt", + "connected_account": { + "object": "connected_account", + "id": "data_installation_01EHZNVPK3SFK441A1RGBFSHRT", + "user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT", + "organization_id": null, + "scopes": [ + "repo", + "user:email" + ], + "state": "connected", + "created_at": "2024-01-16T14:20:00.000Z", + "updated_at": "2024-01-16T14:20:00.000Z", + "userlandUserId": "test_userlandUserId", + "organizationId": "test_organizationId", + "createdAt": "test_createdAt", + "updatedAt": "test_updatedAt" + } + } + ] +} diff --git a/tests/Fixtures/data_integrations_list_response_data.json b/tests/Fixtures/data_integrations_list_response_data.json new file mode 100644 index 00000000..e86e6be1 --- /dev/null +++ b/tests/Fixtures/data_integrations_list_response_data.json @@ -0,0 +1,37 @@ +{ + "object": "data_provider", + "id": "data_integration_01EHZNVPK3SFK441A1RGBFSHRT", + "name": "GitHub", + "description": "Connect your GitHub account to access repositories.", + "slug": "github", + "integration_type": "github", + "credentials_type": "oauth2", + "scopes": [ + "repo", + "user:email" + ], + "ownership": "userland_user", + "created_at": "2024-01-15T10:30:00.000Z", + "updated_at": "2024-01-15T10:30:00.000Z", + "integrationType": "test_integrationType", + "credentialsType": "test_credentialsType", + "createdAt": "test_createdAt", + "updatedAt": "test_updatedAt", + "connected_account": { + "object": "connected_account", + "id": "data_installation_01EHZNVPK3SFK441A1RGBFSHRT", + "user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT", + "organization_id": null, + "scopes": [ + "repo", + "user:email" + ], + "state": "connected", + "created_at": "2024-01-16T14:20:00.000Z", + "updated_at": "2024-01-16T14:20:00.000Z", + "userlandUserId": "test_userlandUserId", + "organizationId": "test_organizationId", + "createdAt": "test_createdAt", + "updatedAt": "test_updatedAt" + } +} diff --git a/tests/Fixtures/data_integrations_list_response_data_connected_account.json b/tests/Fixtures/data_integrations_list_response_data_connected_account.json new file mode 100644 index 00000000..3fb20392 --- /dev/null +++ b/tests/Fixtures/data_integrations_list_response_data_connected_account.json @@ -0,0 +1,17 @@ +{ + "object": "connected_account", + "id": "data_installation_01EHZNVPK3SFK441A1RGBFSHRT", + "user_id": "user_01EHZNVPK3SFK441A1RGBFSHRT", + "organization_id": null, + "scopes": [ + "repo", + "user:email" + ], + "state": "connected", + "created_at": "2024-01-16T14:20:00.000Z", + "updated_at": "2024-01-16T14:20:00.000Z", + "userlandUserId": "test_userlandUserId", + "organizationId": "test_organizationId", + "createdAt": "test_createdAt", + "updatedAt": "test_updatedAt" +} diff --git a/tests/Fixtures/device_authorization_response.json b/tests/Fixtures/device_authorization_response.json new file mode 100644 index 00000000..465fca25 --- /dev/null +++ b/tests/Fixtures/device_authorization_response.json @@ -0,0 +1,8 @@ +{ + "device_code": "CVE2wOfIFK4vhmiDBntpX9s8KT2f0qngpWYL0LGy9HxYgBRXUKIUkZB9BgIFho5h", + "user_code": "BCDF-GHJK", + "verification_uri": "https://authkit_domain/device", + "verification_uri_complete": "https://authkit_domain/device?user_code=BCDF-GHJK", + "expires_in": 300, + "interval": 5 +} diff --git a/tests/Fixtures/device_code_session_authenticate_request.json b/tests/Fixtures/device_code_session_authenticate_request.json new file mode 100644 index 00000000..fd6c75f7 --- /dev/null +++ b/tests/Fixtures/device_code_session_authenticate_request.json @@ -0,0 +1,8 @@ +{ + "client_id": "client_01HXYZ123456789ABCDEFGHIJ", + "grant_type": "urn:ietf:params:oauth:grant-type:device_code", + "device_code": "Ao4fMrDS...", + "ip_address": "203.0.113.42", + "device_id": "device_01HXYZ123456789ABCDEFGHIJ", + "user_agent": "Mozilla/5.0" +} diff --git a/tests/Fixtures/directory.json b/tests/Fixtures/directory.json new file mode 100644 index 00000000..3f9cc198 --- /dev/null +++ b/tests/Fixtures/directory.json @@ -0,0 +1,19 @@ +{ + "object": "directory", + "id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", + "external_key": "sPa12dwRQ", + "type": "gsuite directory", + "state": "linked", + "name": "Foo Corp", + "domain": "foo-corp.com", + "metadata": { + "users": { + "active": 42, + "inactive": 3 + }, + "groups": 5 + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/directory_group.json b/tests/Fixtures/directory_group.json new file mode 100644 index 00000000..d4005ba4 --- /dev/null +++ b/tests/Fixtures/directory_group.json @@ -0,0 +1,13 @@ +{ + "object": "directory_group", + "id": "directory_group_01E1JJS84MFPPQ3G655FHTKX6Z", + "idp_id": "02grqrue4294w24", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "name": "Developers", + "raw_attributes": { + "key": {} + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/directory_group_list_list_metadata.json b/tests/Fixtures/directory_group_list_list_metadata.json new file mode 100644 index 00000000..ef167fbb --- /dev/null +++ b/tests/Fixtures/directory_group_list_list_metadata.json @@ -0,0 +1,4 @@ +{ + "before": "directory_group_01HXYZ123456789ABCDEFGHIJ", + "after": "directory_group_01HXYZ987654321KJIHGFEDCBA" +} diff --git a/tests/Fixtures/directory_list_list_metadata.json b/tests/Fixtures/directory_list_list_metadata.json new file mode 100644 index 00000000..62cf629c --- /dev/null +++ b/tests/Fixtures/directory_list_list_metadata.json @@ -0,0 +1,4 @@ +{ + "before": "directory_01HXYZ123456789ABCDEFGHIJ", + "after": "directory_01HXYZ987654321KJIHGFEDCBA" +} diff --git a/tests/Fixtures/directory_metadata.json b/tests/Fixtures/directory_metadata.json new file mode 100644 index 00000000..0cfc2d4a --- /dev/null +++ b/tests/Fixtures/directory_metadata.json @@ -0,0 +1,7 @@ +{ + "users": { + "active": 42, + "inactive": 3 + }, + "groups": 5 +} diff --git a/tests/Fixtures/directory_metadata_user.json b/tests/Fixtures/directory_metadata_user.json new file mode 100644 index 00000000..0c8d0ae7 --- /dev/null +++ b/tests/Fixtures/directory_metadata_user.json @@ -0,0 +1,4 @@ +{ + "active": 42, + "inactive": 3 +} diff --git a/tests/Fixtures/directory_user.json b/tests/Fixtures/directory_user.json new file mode 100644 index 00000000..68d037ee --- /dev/null +++ b/tests/Fixtures/directory_user.json @@ -0,0 +1,37 @@ +{ + "object": "directory_user", + "id": "directory_user_01E1JG7J09H96KYP8HM9B0G5SJ", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "idp_id": "2836", + "email": "marcelina.davis@example.com", + "first_name": "Marcelina", + "last_name": "Davis", + "emails": [ + { + "primary": true, + "type": "work", + "value": "marcelina.davis@example.com" + } + ], + "job_title": "Software Engineer", + "username": "mdavis", + "state": "active", + "raw_attributes": { + "key": {} + }, + "custom_attributes": { + "department": "Engineering", + "job_title": "Software Engineer" + }, + "role": { + "slug": "admin" + }, + "roles": [ + { + "slug": "admin" + } + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/directory_user_email.json b/tests/Fixtures/directory_user_email.json new file mode 100644 index 00000000..994ff49c --- /dev/null +++ b/tests/Fixtures/directory_user_email.json @@ -0,0 +1,5 @@ +{ + "primary": true, + "type": "work", + "value": "marcelina.davis@example.com" +} diff --git a/tests/Fixtures/directory_user_list_list_metadata.json b/tests/Fixtures/directory_user_list_list_metadata.json new file mode 100644 index 00000000..b470f776 --- /dev/null +++ b/tests/Fixtures/directory_user_list_list_metadata.json @@ -0,0 +1,4 @@ +{ + "before": "directory_user_01HXYZ123456789ABCDEFGHIJ", + "after": "directory_user_01HXYZ987654321KJIHGFEDCBA" +} diff --git a/tests/Fixtures/directory_user_with_groups.json b/tests/Fixtures/directory_user_with_groups.json new file mode 100644 index 00000000..d7d35220 --- /dev/null +++ b/tests/Fixtures/directory_user_with_groups.json @@ -0,0 +1,52 @@ +{ + "object": "directory_user", + "id": "directory_user_01E1JG7J09H96KYP8HM9B0G5SJ", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "idp_id": "2836", + "email": "marcelina.davis@example.com", + "first_name": "Marcelina", + "last_name": "Davis", + "emails": [ + { + "primary": true, + "type": "work", + "value": "marcelina.davis@example.com" + } + ], + "job_title": "Software Engineer", + "username": "mdavis", + "state": "active", + "raw_attributes": { + "key": {} + }, + "custom_attributes": { + "department": "Engineering", + "job_title": "Software Engineer" + }, + "role": { + "slug": "admin" + }, + "roles": [ + { + "slug": "admin" + } + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "groups": [ + { + "object": "directory_group", + "id": "directory_group_01E1JJS84MFPPQ3G655FHTKX6Z", + "idp_id": "02grqrue4294w24", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "name": "Developers", + "raw_attributes": { + "key": {} + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + ] +} diff --git a/tests/Fixtures/directory_user_with_groups_email.json b/tests/Fixtures/directory_user_with_groups_email.json new file mode 100644 index 00000000..994ff49c --- /dev/null +++ b/tests/Fixtures/directory_user_with_groups_email.json @@ -0,0 +1,5 @@ +{ + "primary": true, + "type": "work", + "value": "marcelina.davis@example.com" +} diff --git a/tests/Fixtures/dsync_activated.json b/tests/Fixtures/dsync_activated.json new file mode 100644 index 00000000..ee578f1a --- /dev/null +++ b/tests/Fixtures/dsync_activated.json @@ -0,0 +1,44 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "dsync.activated", + "data": { + "object": "directory", + "id": "directory_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "type": "okta scim v2.0", + "state": "active", + "name": "Acme Directory", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "external_key": "ext_01EHWNCE74X7JSDV0X3SZ3KJNY", + "domains": [ + { + "object": "organization_domain", + "id": "org_domain_01EHWNCE74X7JSDV0X3SZ3KJNY", + "domain": "acme.com" + } + ] + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/dsync_activated_context.json b/tests/Fixtures/dsync_activated_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/dsync_activated_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/dsync_activated_context_actor.json b/tests/Fixtures/dsync_activated_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/dsync_activated_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/dsync_activated_context_google_analytics_session.json b/tests/Fixtures/dsync_activated_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/dsync_activated_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/dsync_activated_data.json b/tests/Fixtures/dsync_activated_data.json new file mode 100644 index 00000000..8b60167d --- /dev/null +++ b/tests/Fixtures/dsync_activated_data.json @@ -0,0 +1,18 @@ +{ + "object": "directory", + "id": "directory_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "type": "okta scim v2.0", + "state": "active", + "name": "Acme Directory", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "external_key": "ext_01EHWNCE74X7JSDV0X3SZ3KJNY", + "domains": [ + { + "object": "organization_domain", + "id": "org_domain_01EHWNCE74X7JSDV0X3SZ3KJNY", + "domain": "acme.com" + } + ] +} diff --git a/tests/Fixtures/dsync_activated_data_domain.json b/tests/Fixtures/dsync_activated_data_domain.json new file mode 100644 index 00000000..2a0132ae --- /dev/null +++ b/tests/Fixtures/dsync_activated_data_domain.json @@ -0,0 +1,5 @@ +{ + "object": "organization_domain", + "id": "org_domain_01EHWNCE74X7JSDV0X3SZ3KJNY", + "domain": "acme.com" +} diff --git a/tests/Fixtures/dsync_deactivated.json b/tests/Fixtures/dsync_deactivated.json new file mode 100644 index 00000000..52780238 --- /dev/null +++ b/tests/Fixtures/dsync_deactivated.json @@ -0,0 +1,44 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "dsync.deactivated", + "data": { + "object": "directory", + "id": "directory_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "type": "okta scim v2.0", + "state": "active", + "name": "Acme Directory", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "external_key": "ext_01EHWNCE74X7JSDV0X3SZ3KJNY", + "domains": [ + { + "object": "organization_domain", + "id": "org_domain_01EHWNCE74X7JSDV0X3SZ3KJNY", + "domain": "acme.com" + } + ] + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/dsync_deactivated_context.json b/tests/Fixtures/dsync_deactivated_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/dsync_deactivated_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/dsync_deactivated_context_actor.json b/tests/Fixtures/dsync_deactivated_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/dsync_deactivated_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/dsync_deactivated_context_google_analytics_session.json b/tests/Fixtures/dsync_deactivated_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/dsync_deactivated_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/dsync_deactivated_data.json b/tests/Fixtures/dsync_deactivated_data.json new file mode 100644 index 00000000..8b60167d --- /dev/null +++ b/tests/Fixtures/dsync_deactivated_data.json @@ -0,0 +1,18 @@ +{ + "object": "directory", + "id": "directory_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "type": "okta scim v2.0", + "state": "active", + "name": "Acme Directory", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "external_key": "ext_01EHWNCE74X7JSDV0X3SZ3KJNY", + "domains": [ + { + "object": "organization_domain", + "id": "org_domain_01EHWNCE74X7JSDV0X3SZ3KJNY", + "domain": "acme.com" + } + ] +} diff --git a/tests/Fixtures/dsync_deactivated_data_domain.json b/tests/Fixtures/dsync_deactivated_data_domain.json new file mode 100644 index 00000000..2a0132ae --- /dev/null +++ b/tests/Fixtures/dsync_deactivated_data_domain.json @@ -0,0 +1,5 @@ +{ + "object": "organization_domain", + "id": "org_domain_01EHWNCE74X7JSDV0X3SZ3KJNY", + "domain": "acme.com" +} diff --git a/tests/Fixtures/dsync_deleted.json b/tests/Fixtures/dsync_deleted.json new file mode 100644 index 00000000..3933e2e0 --- /dev/null +++ b/tests/Fixtures/dsync_deleted.json @@ -0,0 +1,36 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "dsync.deleted", + "data": { + "object": "directory", + "id": "directory_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "type": "okta scim v2.0", + "state": "active", + "name": "Acme Directory", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/dsync_deleted_context.json b/tests/Fixtures/dsync_deleted_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/dsync_deleted_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/dsync_deleted_context_actor.json b/tests/Fixtures/dsync_deleted_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/dsync_deleted_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/dsync_deleted_context_google_analytics_session.json b/tests/Fixtures/dsync_deleted_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/dsync_deleted_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/dsync_deleted_data.json b/tests/Fixtures/dsync_deleted_data.json new file mode 100644 index 00000000..844cc708 --- /dev/null +++ b/tests/Fixtures/dsync_deleted_data.json @@ -0,0 +1,10 @@ +{ + "object": "directory", + "id": "directory_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "type": "okta scim v2.0", + "state": "active", + "name": "Acme Directory", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/dsync_group_created.json b/tests/Fixtures/dsync_group_created.json new file mode 100644 index 00000000..24ff886f --- /dev/null +++ b/tests/Fixtures/dsync_group_created.json @@ -0,0 +1,39 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "dsync.group.created", + "data": { + "object": "directory_group", + "id": "directory_group_01E1JJS84MFPPQ3G655FHTKX6Z", + "idp_id": "02grqrue4294w24", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "name": "Developers", + "raw_attributes": { + "key": {} + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/dsync_group_created_context.json b/tests/Fixtures/dsync_group_created_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/dsync_group_created_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/dsync_group_created_context_actor.json b/tests/Fixtures/dsync_group_created_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/dsync_group_created_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/dsync_group_created_context_google_analytics_session.json b/tests/Fixtures/dsync_group_created_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/dsync_group_created_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/dsync_group_created_data.json b/tests/Fixtures/dsync_group_created_data.json new file mode 100644 index 00000000..d4005ba4 --- /dev/null +++ b/tests/Fixtures/dsync_group_created_data.json @@ -0,0 +1,13 @@ +{ + "object": "directory_group", + "id": "directory_group_01E1JJS84MFPPQ3G655FHTKX6Z", + "idp_id": "02grqrue4294w24", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "name": "Developers", + "raw_attributes": { + "key": {} + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/dsync_group_deleted.json b/tests/Fixtures/dsync_group_deleted.json new file mode 100644 index 00000000..4cd5be17 --- /dev/null +++ b/tests/Fixtures/dsync_group_deleted.json @@ -0,0 +1,39 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "dsync.group.deleted", + "data": { + "object": "directory_group", + "id": "directory_group_01E1JJS84MFPPQ3G655FHTKX6Z", + "idp_id": "02grqrue4294w24", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "name": "Developers", + "raw_attributes": { + "key": {} + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/dsync_group_deleted_context.json b/tests/Fixtures/dsync_group_deleted_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/dsync_group_deleted_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/dsync_group_deleted_context_actor.json b/tests/Fixtures/dsync_group_deleted_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/dsync_group_deleted_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/dsync_group_deleted_context_google_analytics_session.json b/tests/Fixtures/dsync_group_deleted_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/dsync_group_deleted_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/dsync_group_deleted_data.json b/tests/Fixtures/dsync_group_deleted_data.json new file mode 100644 index 00000000..d4005ba4 --- /dev/null +++ b/tests/Fixtures/dsync_group_deleted_data.json @@ -0,0 +1,13 @@ +{ + "object": "directory_group", + "id": "directory_group_01E1JJS84MFPPQ3G655FHTKX6Z", + "idp_id": "02grqrue4294w24", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "name": "Developers", + "raw_attributes": { + "key": {} + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/dsync_group_updated.json b/tests/Fixtures/dsync_group_updated.json new file mode 100644 index 00000000..e3b4376b --- /dev/null +++ b/tests/Fixtures/dsync_group_updated.json @@ -0,0 +1,42 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "dsync.group.updated", + "data": { + "object": "directory_group", + "id": "directory_group_01E1JJS84MFPPQ3G655FHTKX6Z", + "idp_id": "02grqrue4294w24", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "name": "Developers", + "raw_attributes": { + "key": {} + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "previous_attributes": { + "key": {} + } + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/dsync_group_updated_context.json b/tests/Fixtures/dsync_group_updated_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/dsync_group_updated_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/dsync_group_updated_context_actor.json b/tests/Fixtures/dsync_group_updated_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/dsync_group_updated_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/dsync_group_updated_context_google_analytics_session.json b/tests/Fixtures/dsync_group_updated_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/dsync_group_updated_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/dsync_group_updated_data.json b/tests/Fixtures/dsync_group_updated_data.json new file mode 100644 index 00000000..fc4d6531 --- /dev/null +++ b/tests/Fixtures/dsync_group_updated_data.json @@ -0,0 +1,16 @@ +{ + "object": "directory_group", + "id": "directory_group_01E1JJS84MFPPQ3G655FHTKX6Z", + "idp_id": "02grqrue4294w24", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "name": "Developers", + "raw_attributes": { + "key": {} + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/dsync_group_user_added.json b/tests/Fixtures/dsync_group_user_added.json new file mode 100644 index 00000000..61c5aac6 --- /dev/null +++ b/tests/Fixtures/dsync_group_user_added.json @@ -0,0 +1,79 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "dsync.group.user_added", + "data": { + "directory_id": "directory_01EHWNCE74X7JSDV0X3SZ3KJNY", + "user": { + "object": "directory_user", + "id": "directory_user_01E1JG7J09H96KYP8HM9B0G5SJ", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "idp_id": "2836", + "email": "marcelina.davis@example.com", + "first_name": "Marcelina", + "last_name": "Davis", + "emails": [ + { + "primary": true, + "type": "work", + "value": "marcelina.davis@example.com" + } + ], + "job_title": "Software Engineer", + "username": "mdavis", + "state": "active", + "raw_attributes": { + "key": {} + }, + "custom_attributes": { + "department": "Engineering", + "job_title": "Software Engineer" + }, + "role": { + "slug": "admin" + }, + "roles": [ + { + "slug": "admin" + } + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "group": { + "object": "directory_group", + "id": "directory_group_01E1JJS84MFPPQ3G655FHTKX6Z", + "idp_id": "02grqrue4294w24", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "name": "Developers", + "raw_attributes": { + "key": {} + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/dsync_group_user_added_context.json b/tests/Fixtures/dsync_group_user_added_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/dsync_group_user_added_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/dsync_group_user_added_context_actor.json b/tests/Fixtures/dsync_group_user_added_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/dsync_group_user_added_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/dsync_group_user_added_context_google_analytics_session.json b/tests/Fixtures/dsync_group_user_added_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/dsync_group_user_added_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/dsync_group_user_added_data.json b/tests/Fixtures/dsync_group_user_added_data.json new file mode 100644 index 00000000..5ef37883 --- /dev/null +++ b/tests/Fixtures/dsync_group_user_added_data.json @@ -0,0 +1,53 @@ +{ + "directory_id": "directory_01EHWNCE74X7JSDV0X3SZ3KJNY", + "user": { + "object": "directory_user", + "id": "directory_user_01E1JG7J09H96KYP8HM9B0G5SJ", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "idp_id": "2836", + "email": "marcelina.davis@example.com", + "first_name": "Marcelina", + "last_name": "Davis", + "emails": [ + { + "primary": true, + "type": "work", + "value": "marcelina.davis@example.com" + } + ], + "job_title": "Software Engineer", + "username": "mdavis", + "state": "active", + "raw_attributes": { + "key": {} + }, + "custom_attributes": { + "department": "Engineering", + "job_title": "Software Engineer" + }, + "role": { + "slug": "admin" + }, + "roles": [ + { + "slug": "admin" + } + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "group": { + "object": "directory_group", + "id": "directory_group_01E1JJS84MFPPQ3G655FHTKX6Z", + "idp_id": "02grqrue4294w24", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "name": "Developers", + "raw_attributes": { + "key": {} + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } +} diff --git a/tests/Fixtures/dsync_group_user_added_data_group.json b/tests/Fixtures/dsync_group_user_added_data_group.json new file mode 100644 index 00000000..d4005ba4 --- /dev/null +++ b/tests/Fixtures/dsync_group_user_added_data_group.json @@ -0,0 +1,13 @@ +{ + "object": "directory_group", + "id": "directory_group_01E1JJS84MFPPQ3G655FHTKX6Z", + "idp_id": "02grqrue4294w24", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "name": "Developers", + "raw_attributes": { + "key": {} + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/dsync_group_user_added_data_user.json b/tests/Fixtures/dsync_group_user_added_data_user.json new file mode 100644 index 00000000..68d037ee --- /dev/null +++ b/tests/Fixtures/dsync_group_user_added_data_user.json @@ -0,0 +1,37 @@ +{ + "object": "directory_user", + "id": "directory_user_01E1JG7J09H96KYP8HM9B0G5SJ", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "idp_id": "2836", + "email": "marcelina.davis@example.com", + "first_name": "Marcelina", + "last_name": "Davis", + "emails": [ + { + "primary": true, + "type": "work", + "value": "marcelina.davis@example.com" + } + ], + "job_title": "Software Engineer", + "username": "mdavis", + "state": "active", + "raw_attributes": { + "key": {} + }, + "custom_attributes": { + "department": "Engineering", + "job_title": "Software Engineer" + }, + "role": { + "slug": "admin" + }, + "roles": [ + { + "slug": "admin" + } + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/dsync_group_user_added_data_user_email.json b/tests/Fixtures/dsync_group_user_added_data_user_email.json new file mode 100644 index 00000000..994ff49c --- /dev/null +++ b/tests/Fixtures/dsync_group_user_added_data_user_email.json @@ -0,0 +1,5 @@ +{ + "primary": true, + "type": "work", + "value": "marcelina.davis@example.com" +} diff --git a/tests/Fixtures/dsync_group_user_added_data_user_role.json b/tests/Fixtures/dsync_group_user_added_data_user_role.json new file mode 100644 index 00000000..21f8f041 --- /dev/null +++ b/tests/Fixtures/dsync_group_user_added_data_user_role.json @@ -0,0 +1,3 @@ +{ + "slug": "admin" +} diff --git a/tests/Fixtures/dsync_group_user_removed.json b/tests/Fixtures/dsync_group_user_removed.json new file mode 100644 index 00000000..3b991f47 --- /dev/null +++ b/tests/Fixtures/dsync_group_user_removed.json @@ -0,0 +1,79 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "dsync.group.user_removed", + "data": { + "directory_id": "directory_01EHWNCE74X7JSDV0X3SZ3KJNY", + "user": { + "object": "directory_user", + "id": "directory_user_01E1JG7J09H96KYP8HM9B0G5SJ", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "idp_id": "2836", + "email": "marcelina.davis@example.com", + "first_name": "Marcelina", + "last_name": "Davis", + "emails": [ + { + "primary": true, + "type": "work", + "value": "marcelina.davis@example.com" + } + ], + "job_title": "Software Engineer", + "username": "mdavis", + "state": "active", + "raw_attributes": { + "key": {} + }, + "custom_attributes": { + "department": "Engineering", + "job_title": "Software Engineer" + }, + "role": { + "slug": "admin" + }, + "roles": [ + { + "slug": "admin" + } + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "group": { + "object": "directory_group", + "id": "directory_group_01E1JJS84MFPPQ3G655FHTKX6Z", + "idp_id": "02grqrue4294w24", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "name": "Developers", + "raw_attributes": { + "key": {} + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/dsync_group_user_removed_context.json b/tests/Fixtures/dsync_group_user_removed_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/dsync_group_user_removed_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/dsync_group_user_removed_context_actor.json b/tests/Fixtures/dsync_group_user_removed_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/dsync_group_user_removed_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/dsync_group_user_removed_context_google_analytics_session.json b/tests/Fixtures/dsync_group_user_removed_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/dsync_group_user_removed_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/dsync_group_user_removed_data.json b/tests/Fixtures/dsync_group_user_removed_data.json new file mode 100644 index 00000000..5ef37883 --- /dev/null +++ b/tests/Fixtures/dsync_group_user_removed_data.json @@ -0,0 +1,53 @@ +{ + "directory_id": "directory_01EHWNCE74X7JSDV0X3SZ3KJNY", + "user": { + "object": "directory_user", + "id": "directory_user_01E1JG7J09H96KYP8HM9B0G5SJ", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "idp_id": "2836", + "email": "marcelina.davis@example.com", + "first_name": "Marcelina", + "last_name": "Davis", + "emails": [ + { + "primary": true, + "type": "work", + "value": "marcelina.davis@example.com" + } + ], + "job_title": "Software Engineer", + "username": "mdavis", + "state": "active", + "raw_attributes": { + "key": {} + }, + "custom_attributes": { + "department": "Engineering", + "job_title": "Software Engineer" + }, + "role": { + "slug": "admin" + }, + "roles": [ + { + "slug": "admin" + } + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "group": { + "object": "directory_group", + "id": "directory_group_01E1JJS84MFPPQ3G655FHTKX6Z", + "idp_id": "02grqrue4294w24", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "name": "Developers", + "raw_attributes": { + "key": {} + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } +} diff --git a/tests/Fixtures/dsync_group_user_removed_data_group.json b/tests/Fixtures/dsync_group_user_removed_data_group.json new file mode 100644 index 00000000..d4005ba4 --- /dev/null +++ b/tests/Fixtures/dsync_group_user_removed_data_group.json @@ -0,0 +1,13 @@ +{ + "object": "directory_group", + "id": "directory_group_01E1JJS84MFPPQ3G655FHTKX6Z", + "idp_id": "02grqrue4294w24", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "name": "Developers", + "raw_attributes": { + "key": {} + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/dsync_group_user_removed_data_user.json b/tests/Fixtures/dsync_group_user_removed_data_user.json new file mode 100644 index 00000000..68d037ee --- /dev/null +++ b/tests/Fixtures/dsync_group_user_removed_data_user.json @@ -0,0 +1,37 @@ +{ + "object": "directory_user", + "id": "directory_user_01E1JG7J09H96KYP8HM9B0G5SJ", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "idp_id": "2836", + "email": "marcelina.davis@example.com", + "first_name": "Marcelina", + "last_name": "Davis", + "emails": [ + { + "primary": true, + "type": "work", + "value": "marcelina.davis@example.com" + } + ], + "job_title": "Software Engineer", + "username": "mdavis", + "state": "active", + "raw_attributes": { + "key": {} + }, + "custom_attributes": { + "department": "Engineering", + "job_title": "Software Engineer" + }, + "role": { + "slug": "admin" + }, + "roles": [ + { + "slug": "admin" + } + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/dsync_group_user_removed_data_user_email.json b/tests/Fixtures/dsync_group_user_removed_data_user_email.json new file mode 100644 index 00000000..994ff49c --- /dev/null +++ b/tests/Fixtures/dsync_group_user_removed_data_user_email.json @@ -0,0 +1,5 @@ +{ + "primary": true, + "type": "work", + "value": "marcelina.davis@example.com" +} diff --git a/tests/Fixtures/dsync_group_user_removed_data_user_role.json b/tests/Fixtures/dsync_group_user_removed_data_user_role.json new file mode 100644 index 00000000..21f8f041 --- /dev/null +++ b/tests/Fixtures/dsync_group_user_removed_data_user_role.json @@ -0,0 +1,3 @@ +{ + "slug": "admin" +} diff --git a/tests/Fixtures/dsync_user_created.json b/tests/Fixtures/dsync_user_created.json new file mode 100644 index 00000000..aa1bbc76 --- /dev/null +++ b/tests/Fixtures/dsync_user_created.json @@ -0,0 +1,63 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "dsync.user.created", + "data": { + "object": "directory_user", + "id": "directory_user_01E1JG7J09H96KYP8HM9B0G5SJ", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "idp_id": "2836", + "email": "marcelina.davis@example.com", + "first_name": "Marcelina", + "last_name": "Davis", + "emails": [ + { + "primary": true, + "type": "work", + "value": "marcelina.davis@example.com" + } + ], + "job_title": "Software Engineer", + "username": "mdavis", + "state": "active", + "raw_attributes": { + "key": {} + }, + "custom_attributes": { + "department": "Engineering", + "job_title": "Software Engineer" + }, + "role": { + "slug": "admin" + }, + "roles": [ + { + "slug": "admin" + } + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/dsync_user_created_context.json b/tests/Fixtures/dsync_user_created_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/dsync_user_created_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/dsync_user_created_context_actor.json b/tests/Fixtures/dsync_user_created_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/dsync_user_created_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/dsync_user_created_context_google_analytics_session.json b/tests/Fixtures/dsync_user_created_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/dsync_user_created_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/dsync_user_created_data.json b/tests/Fixtures/dsync_user_created_data.json new file mode 100644 index 00000000..68d037ee --- /dev/null +++ b/tests/Fixtures/dsync_user_created_data.json @@ -0,0 +1,37 @@ +{ + "object": "directory_user", + "id": "directory_user_01E1JG7J09H96KYP8HM9B0G5SJ", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "idp_id": "2836", + "email": "marcelina.davis@example.com", + "first_name": "Marcelina", + "last_name": "Davis", + "emails": [ + { + "primary": true, + "type": "work", + "value": "marcelina.davis@example.com" + } + ], + "job_title": "Software Engineer", + "username": "mdavis", + "state": "active", + "raw_attributes": { + "key": {} + }, + "custom_attributes": { + "department": "Engineering", + "job_title": "Software Engineer" + }, + "role": { + "slug": "admin" + }, + "roles": [ + { + "slug": "admin" + } + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/dsync_user_created_data_email.json b/tests/Fixtures/dsync_user_created_data_email.json new file mode 100644 index 00000000..994ff49c --- /dev/null +++ b/tests/Fixtures/dsync_user_created_data_email.json @@ -0,0 +1,5 @@ +{ + "primary": true, + "type": "work", + "value": "marcelina.davis@example.com" +} diff --git a/tests/Fixtures/dsync_user_created_data_role.json b/tests/Fixtures/dsync_user_created_data_role.json new file mode 100644 index 00000000..21f8f041 --- /dev/null +++ b/tests/Fixtures/dsync_user_created_data_role.json @@ -0,0 +1,3 @@ +{ + "slug": "admin" +} diff --git a/tests/Fixtures/dsync_user_deleted.json b/tests/Fixtures/dsync_user_deleted.json new file mode 100644 index 00000000..26942d25 --- /dev/null +++ b/tests/Fixtures/dsync_user_deleted.json @@ -0,0 +1,63 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "dsync.user.deleted", + "data": { + "object": "directory_user", + "id": "directory_user_01E1JG7J09H96KYP8HM9B0G5SJ", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "idp_id": "2836", + "email": "marcelina.davis@example.com", + "first_name": "Marcelina", + "last_name": "Davis", + "emails": [ + { + "primary": true, + "type": "work", + "value": "marcelina.davis@example.com" + } + ], + "job_title": "Software Engineer", + "username": "mdavis", + "state": "active", + "raw_attributes": { + "key": {} + }, + "custom_attributes": { + "department": "Engineering", + "job_title": "Software Engineer" + }, + "role": { + "slug": "admin" + }, + "roles": [ + { + "slug": "admin" + } + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/dsync_user_deleted_context.json b/tests/Fixtures/dsync_user_deleted_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/dsync_user_deleted_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/dsync_user_deleted_context_actor.json b/tests/Fixtures/dsync_user_deleted_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/dsync_user_deleted_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/dsync_user_deleted_context_google_analytics_session.json b/tests/Fixtures/dsync_user_deleted_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/dsync_user_deleted_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/dsync_user_deleted_data.json b/tests/Fixtures/dsync_user_deleted_data.json new file mode 100644 index 00000000..68d037ee --- /dev/null +++ b/tests/Fixtures/dsync_user_deleted_data.json @@ -0,0 +1,37 @@ +{ + "object": "directory_user", + "id": "directory_user_01E1JG7J09H96KYP8HM9B0G5SJ", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "idp_id": "2836", + "email": "marcelina.davis@example.com", + "first_name": "Marcelina", + "last_name": "Davis", + "emails": [ + { + "primary": true, + "type": "work", + "value": "marcelina.davis@example.com" + } + ], + "job_title": "Software Engineer", + "username": "mdavis", + "state": "active", + "raw_attributes": { + "key": {} + }, + "custom_attributes": { + "department": "Engineering", + "job_title": "Software Engineer" + }, + "role": { + "slug": "admin" + }, + "roles": [ + { + "slug": "admin" + } + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/dsync_user_deleted_data_email.json b/tests/Fixtures/dsync_user_deleted_data_email.json new file mode 100644 index 00000000..994ff49c --- /dev/null +++ b/tests/Fixtures/dsync_user_deleted_data_email.json @@ -0,0 +1,5 @@ +{ + "primary": true, + "type": "work", + "value": "marcelina.davis@example.com" +} diff --git a/tests/Fixtures/dsync_user_deleted_data_role.json b/tests/Fixtures/dsync_user_deleted_data_role.json new file mode 100644 index 00000000..21f8f041 --- /dev/null +++ b/tests/Fixtures/dsync_user_deleted_data_role.json @@ -0,0 +1,3 @@ +{ + "slug": "admin" +} diff --git a/tests/Fixtures/dsync_user_updated.json b/tests/Fixtures/dsync_user_updated.json new file mode 100644 index 00000000..6c0266bf --- /dev/null +++ b/tests/Fixtures/dsync_user_updated.json @@ -0,0 +1,66 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "dsync.user.updated", + "data": { + "object": "directory_user", + "id": "directory_user_01E1JG7J09H96KYP8HM9B0G5SJ", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "idp_id": "2836", + "email": "marcelina.davis@example.com", + "first_name": "Marcelina", + "last_name": "Davis", + "emails": [ + { + "primary": true, + "type": "work", + "value": "marcelina.davis@example.com" + } + ], + "job_title": "Software Engineer", + "username": "mdavis", + "state": "active", + "raw_attributes": { + "key": {} + }, + "custom_attributes": { + "department": "Engineering", + "job_title": "Software Engineer" + }, + "role": { + "slug": "admin" + }, + "roles": [ + { + "slug": "admin" + } + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "previous_attributes": { + "key": {} + } + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/dsync_user_updated_context.json b/tests/Fixtures/dsync_user_updated_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/dsync_user_updated_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/dsync_user_updated_context_actor.json b/tests/Fixtures/dsync_user_updated_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/dsync_user_updated_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/dsync_user_updated_context_google_analytics_session.json b/tests/Fixtures/dsync_user_updated_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/dsync_user_updated_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/dsync_user_updated_data.json b/tests/Fixtures/dsync_user_updated_data.json new file mode 100644 index 00000000..0073a535 --- /dev/null +++ b/tests/Fixtures/dsync_user_updated_data.json @@ -0,0 +1,40 @@ +{ + "object": "directory_user", + "id": "directory_user_01E1JG7J09H96KYP8HM9B0G5SJ", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "idp_id": "2836", + "email": "marcelina.davis@example.com", + "first_name": "Marcelina", + "last_name": "Davis", + "emails": [ + { + "primary": true, + "type": "work", + "value": "marcelina.davis@example.com" + } + ], + "job_title": "Software Engineer", + "username": "mdavis", + "state": "active", + "raw_attributes": { + "key": {} + }, + "custom_attributes": { + "department": "Engineering", + "job_title": "Software Engineer" + }, + "role": { + "slug": "admin" + }, + "roles": [ + { + "slug": "admin" + } + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/dsync_user_updated_data_email.json b/tests/Fixtures/dsync_user_updated_data_email.json new file mode 100644 index 00000000..994ff49c --- /dev/null +++ b/tests/Fixtures/dsync_user_updated_data_email.json @@ -0,0 +1,5 @@ +{ + "primary": true, + "type": "work", + "value": "marcelina.davis@example.com" +} diff --git a/tests/Fixtures/dsync_user_updated_data_role.json b/tests/Fixtures/dsync_user_updated_data_role.json new file mode 100644 index 00000000..21f8f041 --- /dev/null +++ b/tests/Fixtures/dsync_user_updated_data_role.json @@ -0,0 +1,3 @@ +{ + "slug": "admin" +} diff --git a/tests/Fixtures/email_change.json b/tests/Fixtures/email_change.json new file mode 100644 index 00000000..41982624 --- /dev/null +++ b/tests/Fixtures/email_change.json @@ -0,0 +1,23 @@ +{ + "object": "email_change", + "user": { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": true, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": { + "timezone": "America/New_York" + }, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "new_email": "new.email@example.com", + "expires_at": "2026-01-15T12:00:00.000Z", + "created_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/email_change_confirmation.json b/tests/Fixtures/email_change_confirmation.json new file mode 100644 index 00000000..5da108ff --- /dev/null +++ b/tests/Fixtures/email_change_confirmation.json @@ -0,0 +1,20 @@ +{ + "object": "email_change_confirmation", + "user": { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "new.email@example.com", + "email_verified": true, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": { + "timezone": "America/New_York" + }, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } +} diff --git a/tests/Fixtures/email_change_confirmation_user.json b/tests/Fixtures/email_change_confirmation_user.json new file mode 100644 index 00000000..dcd50576 --- /dev/null +++ b/tests/Fixtures/email_change_confirmation_user.json @@ -0,0 +1,17 @@ +{ + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "new.email@example.com", + "email_verified": true, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": { + "timezone": "America/New_York" + }, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/email_verification.json b/tests/Fixtures/email_verification.json new file mode 100644 index 00000000..f77aa1db --- /dev/null +++ b/tests/Fixtures/email_verification.json @@ -0,0 +1,10 @@ +{ + "object": "email_verification", + "id": "email_verification_01E4ZCR3C56J083X43JQXF3JK5", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "marcelina.davis@example.com", + "expires_at": "2026-01-15T12:00:00.000Z", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "code": "123456" +} diff --git a/tests/Fixtures/email_verification_code_session_authenticate_request.json b/tests/Fixtures/email_verification_code_session_authenticate_request.json new file mode 100644 index 00000000..47ad4f73 --- /dev/null +++ b/tests/Fixtures/email_verification_code_session_authenticate_request.json @@ -0,0 +1,10 @@ +{ + "client_id": "client_01HXYZ123456789ABCDEFGHIJ", + "client_secret": "sk_test_....", + "grant_type": "urn:workos:oauth:grant-type:email-verification:code", + "code": "123456", + "pending_authentication_token": "cTDQJTTkTkkVYxbn...", + "ip_address": "203.0.113.42", + "device_id": "device_01HXYZ123456789ABCDEFGHIJ", + "user_agent": "Mozilla/5.0" +} diff --git a/tests/Fixtures/email_verification_created.json b/tests/Fixtures/email_verification_created.json new file mode 100644 index 00000000..07569ee6 --- /dev/null +++ b/tests/Fixtures/email_verification_created.json @@ -0,0 +1,35 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "email_verification.created", + "data": { + "object": "email_verification", + "id": "email_verification_01E4ZCR3C56J083X43JQXF3JK5", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "marcelina.davis@example.com", + "expires_at": "2026-01-15T12:00:00.000Z", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/email_verification_created_context.json b/tests/Fixtures/email_verification_created_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/email_verification_created_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/email_verification_created_context_actor.json b/tests/Fixtures/email_verification_created_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/email_verification_created_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/email_verification_created_context_google_analytics_session.json b/tests/Fixtures/email_verification_created_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/email_verification_created_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/email_verification_created_data.json b/tests/Fixtures/email_verification_created_data.json new file mode 100644 index 00000000..9d7c2867 --- /dev/null +++ b/tests/Fixtures/email_verification_created_data.json @@ -0,0 +1,9 @@ +{ + "object": "email_verification", + "id": "email_verification_01E4ZCR3C56J083X43JQXF3JK5", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "marcelina.davis@example.com", + "expires_at": "2026-01-15T12:00:00.000Z", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/enroll_user_authentication_factor.json b/tests/Fixtures/enroll_user_authentication_factor.json new file mode 100644 index 00000000..d6e24611 --- /dev/null +++ b/tests/Fixtures/enroll_user_authentication_factor.json @@ -0,0 +1,6 @@ +{ + "type": "totp", + "totp_issuer": "WorkOS", + "totp_user": "user@example.com", + "totp_secret": "JBSWY3DPEHPK3PXP" +} diff --git a/tests/Fixtures/event_context.json b/tests/Fixtures/event_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/event_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/event_context_actor.json b/tests/Fixtures/event_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/event_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/event_context_google_analytics_session.json b/tests/Fixtures/event_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/event_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/event_list_list_metadata.json b/tests/Fixtures/event_list_list_metadata.json new file mode 100644 index 00000000..7b5eb506 --- /dev/null +++ b/tests/Fixtures/event_list_list_metadata.json @@ -0,0 +1,3 @@ +{ + "after": "event_01EHZNVPK3SFK441A1RGBFSHRT" +} diff --git a/tests/Fixtures/event_schema.json b/tests/Fixtures/event_schema.json new file mode 100644 index 00000000..f3c3b571 --- /dev/null +++ b/tests/Fixtures/event_schema.json @@ -0,0 +1,32 @@ +{ + "object": "event", + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "dsync.user.created", + "data": { + "id": "directory_user_01E1JG7J09H96KYP8HM9B0G5SJ", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "state": "active", + "email": "veda@foo-corp.com", + "emails": [ + { + "primary": true, + "type": "work", + "value": "veda@foo-corp.com" + } + ], + "idp_id": "2836", + "object": "directory_user", + "username": "veda@foo-corp.com", + "last_name": "Torp", + "first_name": "Veda", + "raw_attributes": {}, + "custom_attributes": {}, + "created_at": "2021-06-25T19:07:33.155Z", + "updated_at": "2021-06-25T19:07:33.155Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "key": {} + } +} diff --git a/tests/Fixtures/external_auth_complete_response.json b/tests/Fixtures/external_auth_complete_response.json new file mode 100644 index 00000000..bda60f72 --- /dev/null +++ b/tests/Fixtures/external_auth_complete_response.json @@ -0,0 +1,3 @@ +{ + "redirect_uri": "https://your-authkit-domain.workos.com/oauth/authorize/complete?state=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdGF0ZSI6InJhbmRvbV9zdGF0ZV9zdHJpbmciLCJpYXQiOjE3NDI2MDQ4NTN9.abc123def456ghi789" +} diff --git a/tests/Fixtures/feature_flag.json b/tests/Fixtures/feature_flag.json new file mode 100644 index 00000000..45acfc15 --- /dev/null +++ b/tests/Fixtures/feature_flag.json @@ -0,0 +1,19 @@ +{ + "object": "feature_flag", + "id": "flag_01EHZNVPK3SFK441A1RGBFSHRT", + "slug": "advanced-analytics", + "name": "Advanced Analytics", + "description": "Enable advanced analytics dashboard feature", + "owner": { + "email": "jane@example.com", + "first_name": "Jane", + "last_name": "Doe" + }, + "tags": [ + "reports" + ], + "enabled": false, + "default_value": false, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/feature_flag_owner.json b/tests/Fixtures/feature_flag_owner.json new file mode 100644 index 00000000..7c01c46f --- /dev/null +++ b/tests/Fixtures/feature_flag_owner.json @@ -0,0 +1,5 @@ +{ + "email": "jane@example.com", + "first_name": "Jane", + "last_name": "Doe" +} diff --git a/tests/Fixtures/flag.json b/tests/Fixtures/flag.json new file mode 100644 index 00000000..7b79189a --- /dev/null +++ b/tests/Fixtures/flag.json @@ -0,0 +1,19 @@ +{ + "object": "feature_flag", + "id": "flag_01EHZNVPK3SFK441A1RGBFSHRT", + "slug": "advanced-analytics", + "name": "Advanced Analytics", + "description": "Enable advanced analytics dashboard feature", + "owner": { + "email": "jane@example.com", + "first_name": "Jane", + "last_name": "Doe" + }, + "tags": [ + "reports" + ], + "enabled": true, + "default_value": false, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/flag_created.json b/tests/Fixtures/flag_created.json new file mode 100644 index 00000000..871f9b16 --- /dev/null +++ b/tests/Fixtures/flag_created.json @@ -0,0 +1,34 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "flag.created", + "data": { + "object": "feature_flag", + "id": "flag_01EHZNVPK3SFK441A1RGBFSHRT", + "environment_id": "environment_01EHWNCE74X7JSDV0X3SZ3KJNY", + "slug": "advanced-analytics", + "name": "Advanced Analytics", + "description": "Enable advanced analytics dashboard feature", + "owner": { + "email": "jane@example.com", + "first_name": "Jane", + "last_name": "Doe" + }, + "tags": [ + "reports" + ], + "enabled": true, + "default_value": false, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + } + }, + "object": "event" +} diff --git a/tests/Fixtures/flag_created_context.json b/tests/Fixtures/flag_created_context.json new file mode 100644 index 00000000..8e90e442 --- /dev/null +++ b/tests/Fixtures/flag_created_context.json @@ -0,0 +1,8 @@ +{ + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + } +} diff --git a/tests/Fixtures/flag_created_context_actor.json b/tests/Fixtures/flag_created_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/flag_created_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/flag_created_data.json b/tests/Fixtures/flag_created_data.json new file mode 100644 index 00000000..3167c227 --- /dev/null +++ b/tests/Fixtures/flag_created_data.json @@ -0,0 +1,20 @@ +{ + "object": "feature_flag", + "id": "flag_01EHZNVPK3SFK441A1RGBFSHRT", + "environment_id": "environment_01EHWNCE74X7JSDV0X3SZ3KJNY", + "slug": "advanced-analytics", + "name": "Advanced Analytics", + "description": "Enable advanced analytics dashboard feature", + "owner": { + "email": "jane@example.com", + "first_name": "Jane", + "last_name": "Doe" + }, + "tags": [ + "reports" + ], + "enabled": true, + "default_value": false, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/flag_created_data_owner.json b/tests/Fixtures/flag_created_data_owner.json new file mode 100644 index 00000000..7c01c46f --- /dev/null +++ b/tests/Fixtures/flag_created_data_owner.json @@ -0,0 +1,5 @@ +{ + "email": "jane@example.com", + "first_name": "Jane", + "last_name": "Doe" +} diff --git a/tests/Fixtures/flag_deleted.json b/tests/Fixtures/flag_deleted.json new file mode 100644 index 00000000..b9d6adda --- /dev/null +++ b/tests/Fixtures/flag_deleted.json @@ -0,0 +1,34 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "flag.deleted", + "data": { + "object": "feature_flag", + "id": "flag_01EHZNVPK3SFK441A1RGBFSHRT", + "environment_id": "environment_01EHWNCE74X7JSDV0X3SZ3KJNY", + "slug": "advanced-analytics", + "name": "Advanced Analytics", + "description": "Enable advanced analytics dashboard feature", + "owner": { + "email": "jane@example.com", + "first_name": "Jane", + "last_name": "Doe" + }, + "tags": [ + "reports" + ], + "enabled": true, + "default_value": false, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + } + }, + "object": "event" +} diff --git a/tests/Fixtures/flag_deleted_context.json b/tests/Fixtures/flag_deleted_context.json new file mode 100644 index 00000000..8e90e442 --- /dev/null +++ b/tests/Fixtures/flag_deleted_context.json @@ -0,0 +1,8 @@ +{ + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + } +} diff --git a/tests/Fixtures/flag_deleted_context_actor.json b/tests/Fixtures/flag_deleted_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/flag_deleted_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/flag_deleted_data.json b/tests/Fixtures/flag_deleted_data.json new file mode 100644 index 00000000..3167c227 --- /dev/null +++ b/tests/Fixtures/flag_deleted_data.json @@ -0,0 +1,20 @@ +{ + "object": "feature_flag", + "id": "flag_01EHZNVPK3SFK441A1RGBFSHRT", + "environment_id": "environment_01EHWNCE74X7JSDV0X3SZ3KJNY", + "slug": "advanced-analytics", + "name": "Advanced Analytics", + "description": "Enable advanced analytics dashboard feature", + "owner": { + "email": "jane@example.com", + "first_name": "Jane", + "last_name": "Doe" + }, + "tags": [ + "reports" + ], + "enabled": true, + "default_value": false, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/flag_deleted_data_owner.json b/tests/Fixtures/flag_deleted_data_owner.json new file mode 100644 index 00000000..7c01c46f --- /dev/null +++ b/tests/Fixtures/flag_deleted_data_owner.json @@ -0,0 +1,5 @@ +{ + "email": "jane@example.com", + "first_name": "Jane", + "last_name": "Doe" +} diff --git a/tests/Fixtures/flag_list_list_metadata.json b/tests/Fixtures/flag_list_list_metadata.json new file mode 100644 index 00000000..da9fe789 --- /dev/null +++ b/tests/Fixtures/flag_list_list_metadata.json @@ -0,0 +1,4 @@ +{ + "before": "flag_01HXYZ123456789ABCDEFGHIJ", + "after": "flag_01HXYZ987654321KJIHGFEDCBA" +} diff --git a/tests/Fixtures/flag_owner.json b/tests/Fixtures/flag_owner.json new file mode 100644 index 00000000..7c01c46f --- /dev/null +++ b/tests/Fixtures/flag_owner.json @@ -0,0 +1,5 @@ +{ + "email": "jane@example.com", + "first_name": "Jane", + "last_name": "Doe" +} diff --git a/tests/Fixtures/flag_rule_updated.json b/tests/Fixtures/flag_rule_updated.json new file mode 100644 index 00000000..6f9e5b8c --- /dev/null +++ b/tests/Fixtures/flag_rule_updated.json @@ -0,0 +1,72 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "flag.rule_updated", + "data": { + "object": "feature_flag", + "id": "flag_01EHZNVPK3SFK441A1RGBFSHRT", + "environment_id": "environment_01EHWNCE74X7JSDV0X3SZ3KJNY", + "slug": "advanced-analytics", + "name": "Advanced Analytics", + "description": "Enable advanced analytics dashboard feature", + "owner": { + "email": "jane@example.com", + "first_name": "Jane", + "last_name": "Doe" + }, + "tags": [ + "reports" + ], + "enabled": true, + "default_value": false, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "access_type": "none", + "configured_targets": { + "organizations": [ + { + "id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "name": "Acme Corp" + } + ], + "users": [ + { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "email": "user@example.com" + } + ] + }, + "previous_attributes": { + "data": { + "enabled": true, + "default_value": false + }, + "context": { + "access_type": "none", + "configured_targets": { + "organizations": [ + { + "id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "name": "Acme Corp" + } + ], + "users": [ + { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "email": "user@example.com" + } + ] + } + } + } + }, + "object": "event" +} diff --git a/tests/Fixtures/flag_rule_updated_context.json b/tests/Fixtures/flag_rule_updated_context.json new file mode 100644 index 00000000..45d56248 --- /dev/null +++ b/tests/Fixtures/flag_rule_updated_context.json @@ -0,0 +1,46 @@ +{ + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "access_type": "none", + "configured_targets": { + "organizations": [ + { + "id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "name": "Acme Corp" + } + ], + "users": [ + { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "email": "user@example.com" + } + ] + }, + "previous_attributes": { + "data": { + "enabled": true, + "default_value": false + }, + "context": { + "access_type": "none", + "configured_targets": { + "organizations": [ + { + "id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "name": "Acme Corp" + } + ], + "users": [ + { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "email": "user@example.com" + } + ] + } + } + } +} diff --git a/tests/Fixtures/flag_rule_updated_context_actor.json b/tests/Fixtures/flag_rule_updated_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/flag_rule_updated_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/flag_rule_updated_context_configured_target.json b/tests/Fixtures/flag_rule_updated_context_configured_target.json new file mode 100644 index 00000000..beae8ad9 --- /dev/null +++ b/tests/Fixtures/flag_rule_updated_context_configured_target.json @@ -0,0 +1,14 @@ +{ + "organizations": [ + { + "id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "name": "Acme Corp" + } + ], + "users": [ + { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "email": "user@example.com" + } + ] +} diff --git a/tests/Fixtures/flag_rule_updated_context_configured_target_organization.json b/tests/Fixtures/flag_rule_updated_context_configured_target_organization.json new file mode 100644 index 00000000..8ccf492c --- /dev/null +++ b/tests/Fixtures/flag_rule_updated_context_configured_target_organization.json @@ -0,0 +1,4 @@ +{ + "id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "name": "Acme Corp" +} diff --git a/tests/Fixtures/flag_rule_updated_context_configured_target_user.json b/tests/Fixtures/flag_rule_updated_context_configured_target_user.json new file mode 100644 index 00000000..fb8c1476 --- /dev/null +++ b/tests/Fixtures/flag_rule_updated_context_configured_target_user.json @@ -0,0 +1,4 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "email": "user@example.com" +} diff --git a/tests/Fixtures/flag_rule_updated_context_previous_attribute.json b/tests/Fixtures/flag_rule_updated_context_previous_attribute.json new file mode 100644 index 00000000..061ae2b7 --- /dev/null +++ b/tests/Fixtures/flag_rule_updated_context_previous_attribute.json @@ -0,0 +1,23 @@ +{ + "data": { + "enabled": true, + "default_value": false + }, + "context": { + "access_type": "none", + "configured_targets": { + "organizations": [ + { + "id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "name": "Acme Corp" + } + ], + "users": [ + { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "email": "user@example.com" + } + ] + } + } +} diff --git a/tests/Fixtures/flag_rule_updated_context_previous_attribute_context.json b/tests/Fixtures/flag_rule_updated_context_previous_attribute_context.json new file mode 100644 index 00000000..9b38b382 --- /dev/null +++ b/tests/Fixtures/flag_rule_updated_context_previous_attribute_context.json @@ -0,0 +1,17 @@ +{ + "access_type": "none", + "configured_targets": { + "organizations": [ + { + "id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "name": "Acme Corp" + } + ], + "users": [ + { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "email": "user@example.com" + } + ] + } +} diff --git a/tests/Fixtures/flag_rule_updated_context_previous_attribute_context_configured_target.json b/tests/Fixtures/flag_rule_updated_context_previous_attribute_context_configured_target.json new file mode 100644 index 00000000..beae8ad9 --- /dev/null +++ b/tests/Fixtures/flag_rule_updated_context_previous_attribute_context_configured_target.json @@ -0,0 +1,14 @@ +{ + "organizations": [ + { + "id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "name": "Acme Corp" + } + ], + "users": [ + { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "email": "user@example.com" + } + ] +} diff --git a/tests/Fixtures/flag_rule_updated_context_previous_attribute_context_configured_target_organization.json b/tests/Fixtures/flag_rule_updated_context_previous_attribute_context_configured_target_organization.json new file mode 100644 index 00000000..8ccf492c --- /dev/null +++ b/tests/Fixtures/flag_rule_updated_context_previous_attribute_context_configured_target_organization.json @@ -0,0 +1,4 @@ +{ + "id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "name": "Acme Corp" +} diff --git a/tests/Fixtures/flag_rule_updated_context_previous_attribute_context_configured_target_user.json b/tests/Fixtures/flag_rule_updated_context_previous_attribute_context_configured_target_user.json new file mode 100644 index 00000000..fb8c1476 --- /dev/null +++ b/tests/Fixtures/flag_rule_updated_context_previous_attribute_context_configured_target_user.json @@ -0,0 +1,4 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "email": "user@example.com" +} diff --git a/tests/Fixtures/flag_rule_updated_context_previous_attribute_data.json b/tests/Fixtures/flag_rule_updated_context_previous_attribute_data.json new file mode 100644 index 00000000..705eeaf9 --- /dev/null +++ b/tests/Fixtures/flag_rule_updated_context_previous_attribute_data.json @@ -0,0 +1,4 @@ +{ + "enabled": true, + "default_value": false +} diff --git a/tests/Fixtures/flag_rule_updated_data.json b/tests/Fixtures/flag_rule_updated_data.json new file mode 100644 index 00000000..3167c227 --- /dev/null +++ b/tests/Fixtures/flag_rule_updated_data.json @@ -0,0 +1,20 @@ +{ + "object": "feature_flag", + "id": "flag_01EHZNVPK3SFK441A1RGBFSHRT", + "environment_id": "environment_01EHWNCE74X7JSDV0X3SZ3KJNY", + "slug": "advanced-analytics", + "name": "Advanced Analytics", + "description": "Enable advanced analytics dashboard feature", + "owner": { + "email": "jane@example.com", + "first_name": "Jane", + "last_name": "Doe" + }, + "tags": [ + "reports" + ], + "enabled": true, + "default_value": false, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/flag_rule_updated_data_owner.json b/tests/Fixtures/flag_rule_updated_data_owner.json new file mode 100644 index 00000000..7c01c46f --- /dev/null +++ b/tests/Fixtures/flag_rule_updated_data_owner.json @@ -0,0 +1,5 @@ +{ + "email": "jane@example.com", + "first_name": "Jane", + "last_name": "Doe" +} diff --git a/tests/Fixtures/flag_updated.json b/tests/Fixtures/flag_updated.json new file mode 100644 index 00000000..313b85e7 --- /dev/null +++ b/tests/Fixtures/flag_updated.json @@ -0,0 +1,46 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "flag.updated", + "data": { + "object": "feature_flag", + "id": "flag_01EHZNVPK3SFK441A1RGBFSHRT", + "environment_id": "environment_01EHWNCE74X7JSDV0X3SZ3KJNY", + "slug": "advanced-analytics", + "name": "Advanced Analytics", + "description": "Enable advanced analytics dashboard feature", + "owner": { + "email": "jane@example.com", + "first_name": "Jane", + "last_name": "Doe" + }, + "tags": [ + "reports" + ], + "enabled": true, + "default_value": false, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "data": { + "name": "My Feature Flag", + "description": "Enables the new feature.", + "tags": [ + "beta", + "release" + ], + "enabled": true, + "default_value": false + } + } + }, + "object": "event" +} diff --git a/tests/Fixtures/flag_updated_context.json b/tests/Fixtures/flag_updated_context.json new file mode 100644 index 00000000..498a9fce --- /dev/null +++ b/tests/Fixtures/flag_updated_context.json @@ -0,0 +1,20 @@ +{ + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "data": { + "name": "My Feature Flag", + "description": "Enables the new feature.", + "tags": [ + "beta", + "release" + ], + "enabled": true, + "default_value": false + } + } +} diff --git a/tests/Fixtures/flag_updated_context_actor.json b/tests/Fixtures/flag_updated_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/flag_updated_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/flag_updated_context_previous_attribute.json b/tests/Fixtures/flag_updated_context_previous_attribute.json new file mode 100644 index 00000000..5e18bba3 --- /dev/null +++ b/tests/Fixtures/flag_updated_context_previous_attribute.json @@ -0,0 +1,12 @@ +{ + "data": { + "name": "My Feature Flag", + "description": "Enables the new feature.", + "tags": [ + "beta", + "release" + ], + "enabled": true, + "default_value": false + } +} diff --git a/tests/Fixtures/flag_updated_context_previous_attribute_data.json b/tests/Fixtures/flag_updated_context_previous_attribute_data.json new file mode 100644 index 00000000..959192e3 --- /dev/null +++ b/tests/Fixtures/flag_updated_context_previous_attribute_data.json @@ -0,0 +1,10 @@ +{ + "name": "My Feature Flag", + "description": "Enables the new feature.", + "tags": [ + "beta", + "release" + ], + "enabled": true, + "default_value": false +} diff --git a/tests/Fixtures/flag_updated_data.json b/tests/Fixtures/flag_updated_data.json new file mode 100644 index 00000000..3167c227 --- /dev/null +++ b/tests/Fixtures/flag_updated_data.json @@ -0,0 +1,20 @@ +{ + "object": "feature_flag", + "id": "flag_01EHZNVPK3SFK441A1RGBFSHRT", + "environment_id": "environment_01EHWNCE74X7JSDV0X3SZ3KJNY", + "slug": "advanced-analytics", + "name": "Advanced Analytics", + "description": "Enable advanced analytics dashboard feature", + "owner": { + "email": "jane@example.com", + "first_name": "Jane", + "last_name": "Doe" + }, + "tags": [ + "reports" + ], + "enabled": true, + "default_value": false, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/flag_updated_data_owner.json b/tests/Fixtures/flag_updated_data_owner.json new file mode 100644 index 00000000..7c01c46f --- /dev/null +++ b/tests/Fixtures/flag_updated_data_owner.json @@ -0,0 +1,5 @@ +{ + "email": "jane@example.com", + "first_name": "Jane", + "last_name": "Doe" +} diff --git a/tests/Fixtures/generate_link.json b/tests/Fixtures/generate_link.json new file mode 100644 index 00000000..660b36a7 --- /dev/null +++ b/tests/Fixtures/generate_link.json @@ -0,0 +1,15 @@ +{ + "return_url": "https://example.com/admin-portal/return", + "success_url": "https://example.com/admin-portal/success", + "organization": "org_01EHZNVPK3SFK441A1RGBFSHRT", + "intent": "sso", + "intent_options": { + "sso": { + "bookmark_slug": "chatgpt", + "provider_type": "GoogleSAML" + } + }, + "admin_emails": [ + "admin@example.com" + ] +} diff --git a/tests/Fixtures/intent_options.json b/tests/Fixtures/intent_options.json new file mode 100644 index 00000000..31bad913 --- /dev/null +++ b/tests/Fixtures/intent_options.json @@ -0,0 +1,6 @@ +{ + "sso": { + "bookmark_slug": "chatgpt", + "provider_type": "GoogleSAML" + } +} diff --git a/tests/Fixtures/invitation.json b/tests/Fixtures/invitation.json new file mode 100644 index 00000000..c2019df7 --- /dev/null +++ b/tests/Fixtures/invitation.json @@ -0,0 +1,16 @@ +{ + "object": "invitation", + "id": "invitation_01E4ZCR3C56J083X43JQXF3JK5", + "email": "marcelina.davis@example.com", + "state": "accepted", + "accepted_at": "2026-01-15T12:00:00.000Z", + "revoked_at": null, + "expires_at": "2026-01-15T12:00:00.000Z", + "organization_id": "org_01E4ZCR3C56J083X43JQXF3JK5", + "inviter_user_id": "user_01HYGBX8ZGD19949T3BM4FW1C3", + "accepted_user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "token": "Z1uX3RbwcIl5fIGJJJCXXisdI", + "accept_invitation_url": "https://your-app.com/invite?invitation_token=Z1uX3RbwcIl5fIGJJJCXXisdI" +} diff --git a/tests/Fixtures/invitation_accepted.json b/tests/Fixtures/invitation_accepted.json new file mode 100644 index 00000000..61b93ab4 --- /dev/null +++ b/tests/Fixtures/invitation_accepted.json @@ -0,0 +1,40 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "invitation.accepted", + "data": { + "object": "invitation", + "id": "invitation_01E4ZCR3C56J083X43JQXF3JK5", + "email": "marcelina.davis@example.com", + "state": "pending", + "accepted_at": null, + "revoked_at": null, + "expires_at": "2026-01-15T12:00:00.000Z", + "organization_id": "org_01E4ZCR3C56J083X43JQXF3JK5", + "inviter_user_id": "user_01HYGBX8ZGD19949T3BM4FW1C3", + "accepted_user_id": null, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/invitation_accepted_context.json b/tests/Fixtures/invitation_accepted_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/invitation_accepted_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/invitation_accepted_context_actor.json b/tests/Fixtures/invitation_accepted_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/invitation_accepted_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/invitation_accepted_context_google_analytics_session.json b/tests/Fixtures/invitation_accepted_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/invitation_accepted_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/invitation_accepted_data.json b/tests/Fixtures/invitation_accepted_data.json new file mode 100644 index 00000000..66102c6b --- /dev/null +++ b/tests/Fixtures/invitation_accepted_data.json @@ -0,0 +1,14 @@ +{ + "object": "invitation", + "id": "invitation_01E4ZCR3C56J083X43JQXF3JK5", + "email": "marcelina.davis@example.com", + "state": "pending", + "accepted_at": null, + "revoked_at": null, + "expires_at": "2026-01-15T12:00:00.000Z", + "organization_id": "org_01E4ZCR3C56J083X43JQXF3JK5", + "inviter_user_id": "user_01HYGBX8ZGD19949T3BM4FW1C3", + "accepted_user_id": null, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/invitation_created.json b/tests/Fixtures/invitation_created.json new file mode 100644 index 00000000..c83b104d --- /dev/null +++ b/tests/Fixtures/invitation_created.json @@ -0,0 +1,40 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "invitation.created", + "data": { + "object": "invitation", + "id": "invitation_01E4ZCR3C56J083X43JQXF3JK5", + "email": "marcelina.davis@example.com", + "state": "pending", + "accepted_at": null, + "revoked_at": null, + "expires_at": "2026-01-15T12:00:00.000Z", + "organization_id": "org_01E4ZCR3C56J083X43JQXF3JK5", + "inviter_user_id": "user_01HYGBX8ZGD19949T3BM4FW1C3", + "accepted_user_id": null, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/invitation_created_context.json b/tests/Fixtures/invitation_created_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/invitation_created_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/invitation_created_context_actor.json b/tests/Fixtures/invitation_created_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/invitation_created_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/invitation_created_context_google_analytics_session.json b/tests/Fixtures/invitation_created_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/invitation_created_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/invitation_created_data.json b/tests/Fixtures/invitation_created_data.json new file mode 100644 index 00000000..66102c6b --- /dev/null +++ b/tests/Fixtures/invitation_created_data.json @@ -0,0 +1,14 @@ +{ + "object": "invitation", + "id": "invitation_01E4ZCR3C56J083X43JQXF3JK5", + "email": "marcelina.davis@example.com", + "state": "pending", + "accepted_at": null, + "revoked_at": null, + "expires_at": "2026-01-15T12:00:00.000Z", + "organization_id": "org_01E4ZCR3C56J083X43JQXF3JK5", + "inviter_user_id": "user_01HYGBX8ZGD19949T3BM4FW1C3", + "accepted_user_id": null, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/invitation_resent.json b/tests/Fixtures/invitation_resent.json new file mode 100644 index 00000000..7ace11e7 --- /dev/null +++ b/tests/Fixtures/invitation_resent.json @@ -0,0 +1,40 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "invitation.resent", + "data": { + "object": "invitation", + "id": "invitation_01E4ZCR3C56J083X43JQXF3JK5", + "email": "marcelina.davis@example.com", + "state": "pending", + "accepted_at": null, + "revoked_at": null, + "expires_at": "2026-01-15T12:00:00.000Z", + "organization_id": "org_01E4ZCR3C56J083X43JQXF3JK5", + "inviter_user_id": "user_01HYGBX8ZGD19949T3BM4FW1C3", + "accepted_user_id": null, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/invitation_resent_context.json b/tests/Fixtures/invitation_resent_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/invitation_resent_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/invitation_resent_context_actor.json b/tests/Fixtures/invitation_resent_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/invitation_resent_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/invitation_resent_context_google_analytics_session.json b/tests/Fixtures/invitation_resent_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/invitation_resent_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/invitation_resent_data.json b/tests/Fixtures/invitation_resent_data.json new file mode 100644 index 00000000..66102c6b --- /dev/null +++ b/tests/Fixtures/invitation_resent_data.json @@ -0,0 +1,14 @@ +{ + "object": "invitation", + "id": "invitation_01E4ZCR3C56J083X43JQXF3JK5", + "email": "marcelina.davis@example.com", + "state": "pending", + "accepted_at": null, + "revoked_at": null, + "expires_at": "2026-01-15T12:00:00.000Z", + "organization_id": "org_01E4ZCR3C56J083X43JQXF3JK5", + "inviter_user_id": "user_01HYGBX8ZGD19949T3BM4FW1C3", + "accepted_user_id": null, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/invitation_revoked.json b/tests/Fixtures/invitation_revoked.json new file mode 100644 index 00000000..e8f8ff62 --- /dev/null +++ b/tests/Fixtures/invitation_revoked.json @@ -0,0 +1,40 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "invitation.revoked", + "data": { + "object": "invitation", + "id": "invitation_01E4ZCR3C56J083X43JQXF3JK5", + "email": "marcelina.davis@example.com", + "state": "pending", + "accepted_at": null, + "revoked_at": null, + "expires_at": "2026-01-15T12:00:00.000Z", + "organization_id": "org_01E4ZCR3C56J083X43JQXF3JK5", + "inviter_user_id": "user_01HYGBX8ZGD19949T3BM4FW1C3", + "accepted_user_id": null, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/invitation_revoked_context.json b/tests/Fixtures/invitation_revoked_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/invitation_revoked_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/invitation_revoked_context_actor.json b/tests/Fixtures/invitation_revoked_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/invitation_revoked_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/invitation_revoked_context_google_analytics_session.json b/tests/Fixtures/invitation_revoked_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/invitation_revoked_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/invitation_revoked_data.json b/tests/Fixtures/invitation_revoked_data.json new file mode 100644 index 00000000..66102c6b --- /dev/null +++ b/tests/Fixtures/invitation_revoked_data.json @@ -0,0 +1,14 @@ +{ + "object": "invitation", + "id": "invitation_01E4ZCR3C56J083X43JQXF3JK5", + "email": "marcelina.davis@example.com", + "state": "pending", + "accepted_at": null, + "revoked_at": null, + "expires_at": "2026-01-15T12:00:00.000Z", + "organization_id": "org_01E4ZCR3C56J083X43JQXF3JK5", + "inviter_user_id": "user_01HYGBX8ZGD19949T3BM4FW1C3", + "accepted_user_id": null, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/jwks_response.json b/tests/Fixtures/jwks_response.json new file mode 100644 index 00000000..2e865f38 --- /dev/null +++ b/tests/Fixtures/jwks_response.json @@ -0,0 +1,16 @@ +{ + "keys": [ + { + "alg": "RS256", + "kty": "RSA", + "use": "sig", + "x5c": [ + "MIIDQjCCAiqgAwIBAgIGATz/FuLiMA0GCSqGSIb3DQEBCwUA..." + ], + "n": "0vx7agoebGc...eKnNs", + "e": "AQAB", + "kid": "key_01HXYZ123456789ABCDEFGHIJ", + "x5t#S256": "ZjQzYjI0OT...NmNjU0" + } + ] +} diff --git a/tests/Fixtures/jwks_response_keys.json b/tests/Fixtures/jwks_response_keys.json new file mode 100644 index 00000000..00560836 --- /dev/null +++ b/tests/Fixtures/jwks_response_keys.json @@ -0,0 +1,12 @@ +{ + "alg": "RS256", + "kty": "RSA", + "use": "sig", + "x5c": [ + "MIIDQjCCAiqgAwIBAgIGATz/FuLiMA0GCSqGSIb3DQEBCwUA..." + ], + "n": "0vx7agoebGc...eKnNs", + "e": "AQAB", + "kid": "key_01HXYZ123456789ABCDEFGHIJ", + "x5t#S256": "ZjQzYjI0OT...NmNjU0" +} diff --git a/tests/Fixtures/jwt_template_response.json b/tests/Fixtures/jwt_template_response.json new file mode 100644 index 00000000..b691ce73 --- /dev/null +++ b/tests/Fixtures/jwt_template_response.json @@ -0,0 +1,6 @@ +{ + "object": "jwt_template", + "content": "{\"iss\": \"{{environment.id}}\", \"sub\": \"{{user.id}}\"}", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/list.json b/tests/Fixtures/list.json new file mode 100644 index 00000000..24e16799 --- /dev/null +++ b/tests/Fixtures/list.json @@ -0,0 +1,20 @@ +{ + "object": "list", + "data": [ + { + "slug": "org-admin", + "object": "role", + "id": "role_01EHQMYV6MBK39QC5PZXHY59C3", + "name": "Organization Admin", + "description": "Can manage all resources", + "type": "OrganizationRole", + "resource_type_slug": "default", + "permissions": [ + "posts:read", + "posts:write" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + ] +} diff --git a/tests/Fixtures/list_api_key.json b/tests/Fixtures/list_api_key.json new file mode 100644 index 00000000..f6b9c99c --- /dev/null +++ b/tests/Fixtures/list_api_key.json @@ -0,0 +1,25 @@ +{ + "data": [ + { + "object": "api_key", + "id": "api_key_01EHZNVPK3SFK441A1RGBFSHRT", + "owner": { + "type": "organization", + "id": "org_01EHZNVPK3SFK441A1RGBFSHRT" + }, + "name": "Production API Key", + "obfuscated_value": "sk_...3456", + "last_used_at": null, + "permissions": [ + "posts:read", + "posts:write" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + ], + "list_metadata": { + "before": null, + "after": null + } +} diff --git a/tests/Fixtures/list_audit_log_action_json.json b/tests/Fixtures/list_audit_log_action_json.json new file mode 100644 index 00000000..f36c55df --- /dev/null +++ b/tests/Fixtures/list_audit_log_action_json.json @@ -0,0 +1,50 @@ +{ + "data": [ + { + "object": "audit_log_action", + "name": "user.viewed_invoice", + "schema": { + "object": "audit_log_schema", + "version": 1, + "actor": { + "metadata": { + "type": "object", + "properties": { + "role": { + "type": "string" + } + } + } + }, + "targets": [ + { + "type": "invoice", + "metadata": { + "type": "object", + "properties": { + "cost": { + "type": "number" + } + } + } + } + ], + "metadata": { + "type": "object", + "properties": { + "transactionId": { + "type": "string" + } + } + }, + "created_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + ], + "list_metadata": { + "before": null, + "after": null + } +} diff --git a/tests/Fixtures/list_audit_log_schema_json.json b/tests/Fixtures/list_audit_log_schema_json.json new file mode 100644 index 00000000..97bd6f5b --- /dev/null +++ b/tests/Fixtures/list_audit_log_schema_json.json @@ -0,0 +1,44 @@ +{ + "data": [ + { + "object": "audit_log_schema", + "version": 1, + "actor": { + "metadata": { + "type": "object", + "properties": { + "role": { + "type": "string" + } + } + } + }, + "targets": [ + { + "type": "invoice", + "metadata": { + "type": "object", + "properties": { + "cost": { + "type": "number" + } + } + } + } + ], + "metadata": { + "type": "object", + "properties": { + "transactionId": { + "type": "string" + } + } + }, + "created_at": "2026-01-15T12:00:00.000Z" + } + ], + "list_metadata": { + "before": null, + "after": null + } +} diff --git a/tests/Fixtures/list_authentication_factor.json b/tests/Fixtures/list_authentication_factor.json new file mode 100644 index 00000000..92ce3d94 --- /dev/null +++ b/tests/Fixtures/list_authentication_factor.json @@ -0,0 +1,23 @@ +{ + "data": [ + { + "object": "authentication_factor", + "id": "auth_factor_01FVYZ5QM8N98T9ME5BCB2BBMJ", + "type": "totp", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "sms": { + "phone_number": "+15005550006" + }, + "totp": { + "issuer": "WorkOS", + "user": "user@example.com" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + ], + "list_metadata": { + "before": null, + "after": null + } +} diff --git a/tests/Fixtures/list_authorization_permission.json b/tests/Fixtures/list_authorization_permission.json new file mode 100644 index 00000000..348f9d77 --- /dev/null +++ b/tests/Fixtures/list_authorization_permission.json @@ -0,0 +1,19 @@ +{ + "data": [ + { + "object": "permission", + "id": "perm_01HXYZ123456789ABCDEFGHIJ", + "slug": "documents:read", + "name": "View Documents", + "description": "Allows viewing document contents", + "system": false, + "resource_type_slug": "workspace", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + ], + "list_metadata": { + "before": null, + "after": null + } +} diff --git a/tests/Fixtures/list_authorization_resource.json b/tests/Fixtures/list_authorization_resource.json new file mode 100644 index 00000000..1c184d8a --- /dev/null +++ b/tests/Fixtures/list_authorization_resource.json @@ -0,0 +1,20 @@ +{ + "data": [ + { + "object": "authorization_resource", + "name": "Website Redesign", + "description": "Company website redesign project", + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", + "parent_resource_id": "authz_resource_01HXYZ123456789ABCDEFGHIJ", + "id": "authz_resource_01HXYZ123456789ABCDEFGH", + "external_id": "proj-456", + "resource_type_slug": "project", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + ], + "list_metadata": { + "before": null, + "after": null + } +} diff --git a/tests/Fixtures/list_authorized_connect_application_list_data.json b/tests/Fixtures/list_authorized_connect_application_list_data.json new file mode 100644 index 00000000..d1f30827 --- /dev/null +++ b/tests/Fixtures/list_authorized_connect_application_list_data.json @@ -0,0 +1,31 @@ +{ + "data": [ + { + "object": "authorized_connect_application", + "id": "authorized_connect_app_01HXYZ123456789ABCDEFGHIJ", + "granted_scopes": [ + "openid", + "profile", + "email" + ], + "application": { + "object": "connect_application", + "id": "conn_app_01HXYZ123456789ABCDEFGHIJ", + "client_id": "client_01HXYZ123456789ABCDEFGHIJ", + "description": "An application for managing user access", + "name": "My Application", + "scopes": [ + "openid", + "profile", + "email" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + } + ], + "list_metadata": { + "before": null, + "after": null + } +} diff --git a/tests/Fixtures/list_connect_application.json b/tests/Fixtures/list_connect_application.json new file mode 100644 index 00000000..52900bd8 --- /dev/null +++ b/tests/Fixtures/list_connect_application.json @@ -0,0 +1,22 @@ +{ + "data": [ + { + "object": "connect_application", + "id": "conn_app_01HXYZ123456789ABCDEFGHIJ", + "client_id": "client_01HXYZ123456789ABCDEFGHIJ", + "description": "An application for managing user access", + "name": "My Application", + "scopes": [ + "openid", + "profile", + "email" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + ], + "list_metadata": { + "before": null, + "after": null + } +} diff --git a/tests/Fixtures/list_connection.json b/tests/Fixtures/list_connection.json new file mode 100644 index 00000000..ace19723 --- /dev/null +++ b/tests/Fixtures/list_connection.json @@ -0,0 +1,29 @@ +{ + "data": [ + { + "object": "connection", + "id": "conn_01E4ZCR3C56J083X43JQXF3JK5", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "connection_type": "OktaSAML", + "name": "Foo Corp", + "state": "active", + "status": "linked", + "domains": [ + { + "id": "org_domain_01EHZNVPK2QXHMVWCEDQEKY69A", + "object": "connection_domain", + "domain": "foo-corp.com" + } + ], + "options": { + "signing_cert": null + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + ], + "list_metadata": { + "before": null, + "after": null + } +} diff --git a/tests/Fixtures/list_data.json b/tests/Fixtures/list_data.json new file mode 100644 index 00000000..82458e1c --- /dev/null +++ b/tests/Fixtures/list_data.json @@ -0,0 +1,15 @@ +{ + "slug": "org-admin", + "object": "role", + "id": "role_01EHQMYV6MBK39QC5PZXHY59C3", + "name": "Organization Admin", + "description": "Can manage all resources", + "type": "OrganizationRole", + "resource_type_slug": "default", + "permissions": [ + "posts:read", + "posts:write" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/list_directory.json b/tests/Fixtures/list_directory.json new file mode 100644 index 00000000..e5cb600f --- /dev/null +++ b/tests/Fixtures/list_directory.json @@ -0,0 +1,27 @@ +{ + "data": [ + { + "object": "directory", + "id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", + "external_key": "sPa12dwRQ", + "type": "gsuite directory", + "state": "linked", + "name": "Foo Corp", + "domain": "foo-corp.com", + "metadata": { + "users": { + "active": 42, + "inactive": 3 + }, + "groups": 5 + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + ], + "list_metadata": { + "before": null, + "after": null + } +} diff --git a/tests/Fixtures/list_directory_group.json b/tests/Fixtures/list_directory_group.json new file mode 100644 index 00000000..d83487d5 --- /dev/null +++ b/tests/Fixtures/list_directory_group.json @@ -0,0 +1,21 @@ +{ + "data": [ + { + "object": "directory_group", + "id": "directory_group_01E1JJS84MFPPQ3G655FHTKX6Z", + "idp_id": "02grqrue4294w24", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "name": "Developers", + "raw_attributes": { + "key": {} + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + ], + "list_metadata": { + "before": null, + "after": null + } +} diff --git a/tests/Fixtures/list_directory_user_with_groups.json b/tests/Fixtures/list_directory_user_with_groups.json new file mode 100644 index 00000000..58432bad --- /dev/null +++ b/tests/Fixtures/list_directory_user_with_groups.json @@ -0,0 +1,60 @@ +{ + "data": [ + { + "object": "directory_user", + "id": "directory_user_01E1JG7J09H96KYP8HM9B0G5SJ", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "idp_id": "2836", + "email": "marcelina.davis@example.com", + "first_name": "Marcelina", + "last_name": "Davis", + "emails": [ + { + "primary": true, + "type": "work", + "value": "marcelina.davis@example.com" + } + ], + "job_title": "Software Engineer", + "username": "mdavis", + "state": "active", + "raw_attributes": { + "key": {} + }, + "custom_attributes": { + "department": "Engineering", + "job_title": "Software Engineer" + }, + "role": { + "slug": "admin" + }, + "roles": [ + { + "slug": "admin" + } + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "groups": [ + { + "object": "directory_group", + "id": "directory_group_01E1JJS84MFPPQ3G655FHTKX6Z", + "idp_id": "02grqrue4294w24", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "name": "Developers", + "raw_attributes": { + "key": {} + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + ] + } + ], + "list_metadata": { + "before": null, + "after": null + } +} diff --git a/tests/Fixtures/list_event_schema.json b/tests/Fixtures/list_event_schema.json new file mode 100644 index 00000000..cd8e9bb3 --- /dev/null +++ b/tests/Fixtures/list_event_schema.json @@ -0,0 +1,40 @@ +{ + "data": [ + { + "object": "event", + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "dsync.user.created", + "data": { + "id": "directory_user_01E1JG7J09H96KYP8HM9B0G5SJ", + "directory_id": "directory_01ECAZ4NV9QMV47GW873HDCX74", + "organization_id": "org_01EZTR6WYX1A0DSE2CYMGXQ24Y", + "state": "active", + "email": "veda@foo-corp.com", + "emails": [ + { + "primary": true, + "type": "work", + "value": "veda@foo-corp.com" + } + ], + "idp_id": "2836", + "object": "directory_user", + "username": "veda@foo-corp.com", + "last_name": "Torp", + "first_name": "Veda", + "raw_attributes": {}, + "custom_attributes": {}, + "created_at": "2021-06-25T19:07:33.155Z", + "updated_at": "2021-06-25T19:07:33.155Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "key": {} + } + } + ], + "list_metadata": { + "before": null, + "after": null + } +} diff --git a/tests/Fixtures/list_flag.json b/tests/Fixtures/list_flag.json new file mode 100644 index 00000000..0b85ddbf --- /dev/null +++ b/tests/Fixtures/list_flag.json @@ -0,0 +1,27 @@ +{ + "data": [ + { + "object": "feature_flag", + "id": "flag_01EHZNVPK3SFK441A1RGBFSHRT", + "slug": "advanced-analytics", + "name": "Advanced Analytics", + "description": "Enable advanced analytics dashboard feature", + "owner": { + "email": "jane@example.com", + "first_name": "Jane", + "last_name": "Doe" + }, + "tags": [ + "reports" + ], + "enabled": true, + "default_value": false, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + ], + "list_metadata": { + "before": null, + "after": null + } +} diff --git a/tests/Fixtures/list_organization.json b/tests/Fixtures/list_organization.json new file mode 100644 index 00000000..60eb366a --- /dev/null +++ b/tests/Fixtures/list_organization.json @@ -0,0 +1,35 @@ +{ + "data": [ + { + "object": "organization", + "id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "name": "Acme Inc.", + "domains": [ + { + "object": "organization_domain", + "id": "org_domain_01EHZNVPK2QXHMVWCEDQEKY69A", + "organization_id": "org_01HE8GSH8FQPASKSY27THRKRBP", + "domain": "foo-corp.com", + "state": "pending", + "verification_prefix": "superapp-domain-verification-z3kjny", + "verification_token": "m5Oztg3jdK4NJLgs8uIlIprMw", + "verification_strategy": "dns", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + ], + "metadata": { + "tier": "diamond" + }, + "external_id": "2fe01467-f7ea-4dd2-8b79-c2b4f56d0191", + "stripe_customer_id": "cus_R9qWAGMQ6nGE7V", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "allow_profiles_outside_organization": false + } + ], + "list_metadata": { + "before": null, + "after": null + } +} diff --git a/tests/Fixtures/list_role_assignment.json b/tests/Fixtures/list_role_assignment.json new file mode 100644 index 00000000..81b4468c --- /dev/null +++ b/tests/Fixtures/list_role_assignment.json @@ -0,0 +1,22 @@ +{ + "data": [ + { + "object": "role_assignment", + "id": "role_assignment_01HXYZ123456789ABCDEFGH", + "role": { + "slug": "admin" + }, + "resource": { + "id": "authz_resource_01HXYZ123456789ABCDEFGH", + "external_id": "proj-456", + "resource_type_slug": "project" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + ], + "list_metadata": { + "before": null, + "after": null + } +} diff --git a/tests/Fixtures/list_user.json b/tests/Fixtures/list_user.json new file mode 100644 index 00000000..390c74f9 --- /dev/null +++ b/tests/Fixtures/list_user.json @@ -0,0 +1,25 @@ +{ + "data": [ + { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": true, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": { + "timezone": "America/New_York" + }, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + ], + "list_metadata": { + "before": null, + "after": null + } +} diff --git a/tests/Fixtures/list_user_invite.json b/tests/Fixtures/list_user_invite.json new file mode 100644 index 00000000..355f3e44 --- /dev/null +++ b/tests/Fixtures/list_user_invite.json @@ -0,0 +1,24 @@ +{ + "data": [ + { + "object": "invitation", + "id": "invitation_01E4ZCR3C56J083X43JQXF3JK5", + "email": "marcelina.davis@example.com", + "state": "pending", + "accepted_at": null, + "revoked_at": null, + "expires_at": "2026-01-15T12:00:00.000Z", + "organization_id": "org_01E4ZCR3C56J083X43JQXF3JK5", + "inviter_user_id": "user_01HYGBX8ZGD19949T3BM4FW1C3", + "accepted_user_id": null, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "token": "Z1uX3RbwcIl5fIGJJJCXXisdI", + "accept_invitation_url": "https://your-app.com/invite?invitation_token=Z1uX3RbwcIl5fIGJJJCXXisdI" + } + ], + "list_metadata": { + "before": null, + "after": null + } +} diff --git a/tests/Fixtures/list_user_organization_membership.json b/tests/Fixtures/list_user_organization_membership.json new file mode 100644 index 00000000..cdb823aa --- /dev/null +++ b/tests/Fixtures/list_user_organization_membership.json @@ -0,0 +1,27 @@ +{ + "data": [ + { + "object": "organization_membership", + "id": "om_01HXYZ123456789ABCDEFGHIJ", + "user_id": "user_01EHQTV6MWP9P1F4ZXGXMC8ABB", + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", + "status": "active", + "directory_managed": false, + "organization_name": "Acme Corp", + "custom_attributes": { + "department": "Engineering", + "title": "Developer Experience Engineer", + "location": "Brooklyn" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "role": { + "slug": "admin" + } + } + ], + "list_metadata": { + "before": null, + "after": null + } +} diff --git a/tests/Fixtures/list_user_organization_membership_base_list_data.json b/tests/Fixtures/list_user_organization_membership_base_list_data.json new file mode 100644 index 00000000..b992a1b9 --- /dev/null +++ b/tests/Fixtures/list_user_organization_membership_base_list_data.json @@ -0,0 +1,24 @@ +{ + "data": [ + { + "object": "organization_membership", + "id": "om_01HXYZ123456789ABCDEFGHIJ", + "user_id": "user_01EHQTV6MWP9P1F4ZXGXMC8ABB", + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", + "status": "active", + "directory_managed": false, + "organization_name": "Acme Corp", + "custom_attributes": { + "department": "Engineering", + "title": "Developer Experience Engineer", + "location": "Brooklyn" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + ], + "list_metadata": { + "before": null, + "after": null + } +} diff --git a/tests/Fixtures/list_user_sessions_list_item.json b/tests/Fixtures/list_user_sessions_list_item.json new file mode 100644 index 00000000..2da7cf43 --- /dev/null +++ b/tests/Fixtures/list_user_sessions_list_item.json @@ -0,0 +1,26 @@ +{ + "data": [ + { + "object": "session", + "id": "session_01H93ZY4F80QPBEZ1R5B2SHQG8", + "impersonator": { + "email": "admin@foocorp.com", + "reason": "Investigating an issue with the customer's account." + }, + "ip_address": "198.51.100.42", + "organization_id": "org_01H945H0YD4F97JN9MATX7BYAG", + "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "auth_method": "sso", + "status": "active", + "expires_at": "2026-01-15T12:00:00.000Z", + "ended_at": null, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + ], + "list_metadata": { + "before": null, + "after": null + } +} diff --git a/tests/Fixtures/list_webhook_endpoint_json.json b/tests/Fixtures/list_webhook_endpoint_json.json new file mode 100644 index 00000000..52f8410b --- /dev/null +++ b/tests/Fixtures/list_webhook_endpoint_json.json @@ -0,0 +1,21 @@ +{ + "data": [ + { + "object": "webhook_endpoint", + "id": "we_0123456789", + "endpoint_url": "https://example.com/webhooks", + "secret": "whsec_0FWAiVGkEfGBqqsJH4aNAGBJ4", + "status": "enabled", + "events": [ + "user.created", + "dsync.user.created" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + ], + "list_metadata": { + "before": null, + "after": null + } +} diff --git a/tests/Fixtures/magic_auth.json b/tests/Fixtures/magic_auth.json new file mode 100644 index 00000000..782a3e91 --- /dev/null +++ b/tests/Fixtures/magic_auth.json @@ -0,0 +1,10 @@ +{ + "object": "magic_auth", + "id": "magic_auth_01HWZBQZY2M3AMQW166Q22K88F", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "marcelina.davis@example.com", + "expires_at": "2026-01-15T12:00:00.000Z", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "code": "123456" +} diff --git a/tests/Fixtures/magic_auth_code_session_authenticate_request.json b/tests/Fixtures/magic_auth_code_session_authenticate_request.json new file mode 100644 index 00000000..ebd5511b --- /dev/null +++ b/tests/Fixtures/magic_auth_code_session_authenticate_request.json @@ -0,0 +1,11 @@ +{ + "client_id": "client_01HXYZ123456789ABCDEFGHIJ", + "client_secret": "sk_test_....", + "grant_type": "urn:workos:oauth:grant-type:magic-auth:code", + "code": "123456", + "email": "user@example.com", + "invitation_token": "inv_tok_01HXYZ123456789ABCDEFGHIJ", + "ip_address": "203.0.113.42", + "device_id": "device_01HXYZ123456789ABCDEFGHIJ", + "user_agent": "Mozilla/5.0" +} diff --git a/tests/Fixtures/magic_auth_created.json b/tests/Fixtures/magic_auth_created.json new file mode 100644 index 00000000..145aaef4 --- /dev/null +++ b/tests/Fixtures/magic_auth_created.json @@ -0,0 +1,35 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "magic_auth.created", + "data": { + "object": "magic_auth", + "id": "magic_auth_01HWZBQZY2M3AMQW166Q22K88F", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "marcelina.davis@example.com", + "expires_at": "2026-01-15T12:00:00.000Z", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/magic_auth_created_context.json b/tests/Fixtures/magic_auth_created_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/magic_auth_created_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/magic_auth_created_context_actor.json b/tests/Fixtures/magic_auth_created_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/magic_auth_created_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/magic_auth_created_context_google_analytics_session.json b/tests/Fixtures/magic_auth_created_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/magic_auth_created_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/magic_auth_created_data.json b/tests/Fixtures/magic_auth_created_data.json new file mode 100644 index 00000000..77748326 --- /dev/null +++ b/tests/Fixtures/magic_auth_created_data.json @@ -0,0 +1,9 @@ +{ + "object": "magic_auth", + "id": "magic_auth_01HWZBQZY2M3AMQW166Q22K88F", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "marcelina.davis@example.com", + "expires_at": "2026-01-15T12:00:00.000Z", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/mfa_totp_session_authenticate_request.json b/tests/Fixtures/mfa_totp_session_authenticate_request.json new file mode 100644 index 00000000..31382557 --- /dev/null +++ b/tests/Fixtures/mfa_totp_session_authenticate_request.json @@ -0,0 +1,11 @@ +{ + "client_id": "client_01HXYZ123456789ABCDEFGHIJ", + "client_secret": "sk_test_....", + "grant_type": "urn:workos:oauth:grant-type:mfa-totp", + "code": "123456", + "pending_authentication_token": "cTDQJTTkTkkVYxbn...", + "authentication_challenge_id": "auth_challenge_01HXYZ123456789ABCDEFGHIJ", + "ip_address": "203.0.113.42", + "device_id": "device_01HXYZ123456789ABCDEFGHIJ", + "user_agent": "Mozilla/5.0" +} diff --git a/tests/Fixtures/new_connect_application_secret.json b/tests/Fixtures/new_connect_application_secret.json new file mode 100644 index 00000000..9b772b11 --- /dev/null +++ b/tests/Fixtures/new_connect_application_secret.json @@ -0,0 +1,9 @@ +{ + "object": "connect_application_secret", + "id": "secret_01J9Q2Z3X4Y5W6V7U8T9S0R1Q", + "secret_hint": "abc123", + "last_used_at": null, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "secret": "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz" +} diff --git a/tests/Fixtures/organization.json b/tests/Fixtures/organization.json new file mode 100644 index 00000000..39eaa6fb --- /dev/null +++ b/tests/Fixtures/organization.json @@ -0,0 +1,27 @@ +{ + "object": "organization", + "id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "name": "Acme Inc.", + "domains": [ + { + "object": "organization_domain", + "id": "org_domain_01EHZNVPK2QXHMVWCEDQEKY69A", + "organization_id": "org_01HE8GSH8FQPASKSY27THRKRBP", + "domain": "foo-corp.com", + "state": "pending", + "verification_prefix": "superapp-domain-verification-z3kjny", + "verification_token": "m5Oztg3jdK4NJLgs8uIlIprMw", + "verification_strategy": "dns", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + ], + "metadata": { + "tier": "diamond" + }, + "external_id": "2fe01467-f7ea-4dd2-8b79-c2b4f56d0191", + "stripe_customer_id": "cus_R9qWAGMQ6nGE7V", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "allow_profiles_outside_organization": false +} diff --git a/tests/Fixtures/organization_created.json b/tests/Fixtures/organization_created.json new file mode 100644 index 00000000..0bd57d10 --- /dev/null +++ b/tests/Fixtures/organization_created.json @@ -0,0 +1,52 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "organization.created", + "data": { + "object": "organization", + "id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "name": "Acme Inc.", + "domains": [ + { + "object": "organization_domain", + "id": "org_domain_01EHZNVPK2QXHMVWCEDQEKY69A", + "organization_id": "org_01HE8GSH8FQPASKSY27THRKRBP", + "domain": "foo-corp.com", + "state": "pending", + "verification_prefix": "superapp-domain-verification-z3kjny", + "verification_token": "m5Oztg3jdK4NJLgs8uIlIprMw", + "verification_strategy": "dns", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + ], + "metadata": { + "tier": "diamond" + }, + "external_id": "2fe01467-f7ea-4dd2-8b79-c2b4f56d0191", + "stripe_customer_id": "cus_R9qWAGMQ6nGE7V", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/organization_created_context.json b/tests/Fixtures/organization_created_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/organization_created_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/organization_created_context_actor.json b/tests/Fixtures/organization_created_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/organization_created_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/organization_created_context_google_analytics_session.json b/tests/Fixtures/organization_created_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/organization_created_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/organization_created_data.json b/tests/Fixtures/organization_created_data.json new file mode 100644 index 00000000..71f863b4 --- /dev/null +++ b/tests/Fixtures/organization_created_data.json @@ -0,0 +1,26 @@ +{ + "object": "organization", + "id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "name": "Acme Inc.", + "domains": [ + { + "object": "organization_domain", + "id": "org_domain_01EHZNVPK2QXHMVWCEDQEKY69A", + "organization_id": "org_01HE8GSH8FQPASKSY27THRKRBP", + "domain": "foo-corp.com", + "state": "pending", + "verification_prefix": "superapp-domain-verification-z3kjny", + "verification_token": "m5Oztg3jdK4NJLgs8uIlIprMw", + "verification_strategy": "dns", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + ], + "metadata": { + "tier": "diamond" + }, + "external_id": "2fe01467-f7ea-4dd2-8b79-c2b4f56d0191", + "stripe_customer_id": "cus_R9qWAGMQ6nGE7V", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/organization_created_data_domain.json b/tests/Fixtures/organization_created_data_domain.json new file mode 100644 index 00000000..9bc0c0a1 --- /dev/null +++ b/tests/Fixtures/organization_created_data_domain.json @@ -0,0 +1,12 @@ +{ + "object": "organization_domain", + "id": "org_domain_01EHZNVPK2QXHMVWCEDQEKY69A", + "organization_id": "org_01HE8GSH8FQPASKSY27THRKRBP", + "domain": "foo-corp.com", + "state": "pending", + "verification_prefix": "superapp-domain-verification-z3kjny", + "verification_token": "m5Oztg3jdK4NJLgs8uIlIprMw", + "verification_strategy": "dns", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/organization_deleted.json b/tests/Fixtures/organization_deleted.json new file mode 100644 index 00000000..3d76fa68 --- /dev/null +++ b/tests/Fixtures/organization_deleted.json @@ -0,0 +1,52 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "organization.deleted", + "data": { + "object": "organization", + "id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "name": "Acme Inc.", + "domains": [ + { + "object": "organization_domain", + "id": "org_domain_01EHZNVPK2QXHMVWCEDQEKY69A", + "organization_id": "org_01HE8GSH8FQPASKSY27THRKRBP", + "domain": "foo-corp.com", + "state": "pending", + "verification_prefix": "superapp-domain-verification-z3kjny", + "verification_token": "m5Oztg3jdK4NJLgs8uIlIprMw", + "verification_strategy": "dns", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + ], + "metadata": { + "tier": "diamond" + }, + "external_id": "2fe01467-f7ea-4dd2-8b79-c2b4f56d0191", + "stripe_customer_id": "cus_R9qWAGMQ6nGE7V", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/organization_deleted_context.json b/tests/Fixtures/organization_deleted_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/organization_deleted_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/organization_deleted_context_actor.json b/tests/Fixtures/organization_deleted_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/organization_deleted_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/organization_deleted_context_google_analytics_session.json b/tests/Fixtures/organization_deleted_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/organization_deleted_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/organization_deleted_data.json b/tests/Fixtures/organization_deleted_data.json new file mode 100644 index 00000000..71f863b4 --- /dev/null +++ b/tests/Fixtures/organization_deleted_data.json @@ -0,0 +1,26 @@ +{ + "object": "organization", + "id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "name": "Acme Inc.", + "domains": [ + { + "object": "organization_domain", + "id": "org_domain_01EHZNVPK2QXHMVWCEDQEKY69A", + "organization_id": "org_01HE8GSH8FQPASKSY27THRKRBP", + "domain": "foo-corp.com", + "state": "pending", + "verification_prefix": "superapp-domain-verification-z3kjny", + "verification_token": "m5Oztg3jdK4NJLgs8uIlIprMw", + "verification_strategy": "dns", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + ], + "metadata": { + "tier": "diamond" + }, + "external_id": "2fe01467-f7ea-4dd2-8b79-c2b4f56d0191", + "stripe_customer_id": "cus_R9qWAGMQ6nGE7V", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/organization_deleted_data_domain.json b/tests/Fixtures/organization_deleted_data_domain.json new file mode 100644 index 00000000..9bc0c0a1 --- /dev/null +++ b/tests/Fixtures/organization_deleted_data_domain.json @@ -0,0 +1,12 @@ +{ + "object": "organization_domain", + "id": "org_domain_01EHZNVPK2QXHMVWCEDQEKY69A", + "organization_id": "org_01HE8GSH8FQPASKSY27THRKRBP", + "domain": "foo-corp.com", + "state": "pending", + "verification_prefix": "superapp-domain-verification-z3kjny", + "verification_token": "m5Oztg3jdK4NJLgs8uIlIprMw", + "verification_strategy": "dns", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/organization_domain.json b/tests/Fixtures/organization_domain.json new file mode 100644 index 00000000..9bc0c0a1 --- /dev/null +++ b/tests/Fixtures/organization_domain.json @@ -0,0 +1,12 @@ +{ + "object": "organization_domain", + "id": "org_domain_01EHZNVPK2QXHMVWCEDQEKY69A", + "organization_id": "org_01HE8GSH8FQPASKSY27THRKRBP", + "domain": "foo-corp.com", + "state": "pending", + "verification_prefix": "superapp-domain-verification-z3kjny", + "verification_token": "m5Oztg3jdK4NJLgs8uIlIprMw", + "verification_strategy": "dns", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/organization_domain_created.json b/tests/Fixtures/organization_domain_created.json new file mode 100644 index 00000000..579580b8 --- /dev/null +++ b/tests/Fixtures/organization_domain_created.json @@ -0,0 +1,38 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "organization_domain.created", + "data": { + "object": "organization_domain", + "id": "org_domain_01EHZNVPK2QXHMVWCEDQEKY69A", + "organization_id": "org_01HE8GSH8FQPASKSY27THRKRBP", + "domain": "foo-corp.com", + "state": "pending", + "verification_prefix": "superapp-domain-verification-z3kjny", + "verification_token": "m5Oztg3jdK4NJLgs8uIlIprMw", + "verification_strategy": "dns", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/organization_domain_created_context.json b/tests/Fixtures/organization_domain_created_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/organization_domain_created_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/organization_domain_created_context_actor.json b/tests/Fixtures/organization_domain_created_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/organization_domain_created_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/organization_domain_created_context_google_analytics_session.json b/tests/Fixtures/organization_domain_created_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/organization_domain_created_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/organization_domain_created_data.json b/tests/Fixtures/organization_domain_created_data.json new file mode 100644 index 00000000..9bc0c0a1 --- /dev/null +++ b/tests/Fixtures/organization_domain_created_data.json @@ -0,0 +1,12 @@ +{ + "object": "organization_domain", + "id": "org_domain_01EHZNVPK2QXHMVWCEDQEKY69A", + "organization_id": "org_01HE8GSH8FQPASKSY27THRKRBP", + "domain": "foo-corp.com", + "state": "pending", + "verification_prefix": "superapp-domain-verification-z3kjny", + "verification_token": "m5Oztg3jdK4NJLgs8uIlIprMw", + "verification_strategy": "dns", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/organization_domain_data.json b/tests/Fixtures/organization_domain_data.json new file mode 100644 index 00000000..f0032cb0 --- /dev/null +++ b/tests/Fixtures/organization_domain_data.json @@ -0,0 +1,4 @@ +{ + "domain": "foo-corp.com", + "state": "verified" +} diff --git a/tests/Fixtures/organization_domain_deleted.json b/tests/Fixtures/organization_domain_deleted.json new file mode 100644 index 00000000..1e7e7476 --- /dev/null +++ b/tests/Fixtures/organization_domain_deleted.json @@ -0,0 +1,38 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "organization_domain.deleted", + "data": { + "object": "organization_domain", + "id": "org_domain_01EHZNVPK2QXHMVWCEDQEKY69A", + "organization_id": "org_01HE8GSH8FQPASKSY27THRKRBP", + "domain": "foo-corp.com", + "state": "pending", + "verification_prefix": "superapp-domain-verification-z3kjny", + "verification_token": "m5Oztg3jdK4NJLgs8uIlIprMw", + "verification_strategy": "dns", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/organization_domain_deleted_context.json b/tests/Fixtures/organization_domain_deleted_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/organization_domain_deleted_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/organization_domain_deleted_context_actor.json b/tests/Fixtures/organization_domain_deleted_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/organization_domain_deleted_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/organization_domain_deleted_context_google_analytics_session.json b/tests/Fixtures/organization_domain_deleted_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/organization_domain_deleted_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/organization_domain_deleted_data.json b/tests/Fixtures/organization_domain_deleted_data.json new file mode 100644 index 00000000..9bc0c0a1 --- /dev/null +++ b/tests/Fixtures/organization_domain_deleted_data.json @@ -0,0 +1,12 @@ +{ + "object": "organization_domain", + "id": "org_domain_01EHZNVPK2QXHMVWCEDQEKY69A", + "organization_id": "org_01HE8GSH8FQPASKSY27THRKRBP", + "domain": "foo-corp.com", + "state": "pending", + "verification_prefix": "superapp-domain-verification-z3kjny", + "verification_token": "m5Oztg3jdK4NJLgs8uIlIprMw", + "verification_strategy": "dns", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/organization_domain_stand_alone.json b/tests/Fixtures/organization_domain_stand_alone.json new file mode 100644 index 00000000..9bc0c0a1 --- /dev/null +++ b/tests/Fixtures/organization_domain_stand_alone.json @@ -0,0 +1,12 @@ +{ + "object": "organization_domain", + "id": "org_domain_01EHZNVPK2QXHMVWCEDQEKY69A", + "organization_id": "org_01HE8GSH8FQPASKSY27THRKRBP", + "domain": "foo-corp.com", + "state": "pending", + "verification_prefix": "superapp-domain-verification-z3kjny", + "verification_token": "m5Oztg3jdK4NJLgs8uIlIprMw", + "verification_strategy": "dns", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/organization_domain_updated.json b/tests/Fixtures/organization_domain_updated.json new file mode 100644 index 00000000..a4851a97 --- /dev/null +++ b/tests/Fixtures/organization_domain_updated.json @@ -0,0 +1,38 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "organization_domain.updated", + "data": { + "object": "organization_domain", + "id": "org_domain_01EHZNVPK2QXHMVWCEDQEKY69A", + "organization_id": "org_01HE8GSH8FQPASKSY27THRKRBP", + "domain": "foo-corp.com", + "state": "pending", + "verification_prefix": "superapp-domain-verification-z3kjny", + "verification_token": "m5Oztg3jdK4NJLgs8uIlIprMw", + "verification_strategy": "dns", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/organization_domain_updated_context.json b/tests/Fixtures/organization_domain_updated_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/organization_domain_updated_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/organization_domain_updated_context_actor.json b/tests/Fixtures/organization_domain_updated_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/organization_domain_updated_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/organization_domain_updated_context_google_analytics_session.json b/tests/Fixtures/organization_domain_updated_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/organization_domain_updated_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/organization_domain_updated_data.json b/tests/Fixtures/organization_domain_updated_data.json new file mode 100644 index 00000000..9bc0c0a1 --- /dev/null +++ b/tests/Fixtures/organization_domain_updated_data.json @@ -0,0 +1,12 @@ +{ + "object": "organization_domain", + "id": "org_domain_01EHZNVPK2QXHMVWCEDQEKY69A", + "organization_id": "org_01HE8GSH8FQPASKSY27THRKRBP", + "domain": "foo-corp.com", + "state": "pending", + "verification_prefix": "superapp-domain-verification-z3kjny", + "verification_token": "m5Oztg3jdK4NJLgs8uIlIprMw", + "verification_strategy": "dns", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/organization_domain_verification_failed.json b/tests/Fixtures/organization_domain_verification_failed.json new file mode 100644 index 00000000..fe89780d --- /dev/null +++ b/tests/Fixtures/organization_domain_verification_failed.json @@ -0,0 +1,41 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "organization_domain.verification_failed", + "data": { + "reason": "domain_verification_period_expired", + "organization_domain": { + "object": "organization_domain", + "id": "org_domain_01EHZNVPK2QXHMVWCEDQEKY69A", + "organization_id": "org_01HE8GSH8FQPASKSY27THRKRBP", + "domain": "foo-corp.com", + "state": "pending", + "verification_prefix": "superapp-domain-verification-z3kjny", + "verification_token": "m5Oztg3jdK4NJLgs8uIlIprMw", + "verification_strategy": "dns", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/organization_domain_verification_failed_context.json b/tests/Fixtures/organization_domain_verification_failed_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/organization_domain_verification_failed_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/organization_domain_verification_failed_context_actor.json b/tests/Fixtures/organization_domain_verification_failed_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/organization_domain_verification_failed_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/organization_domain_verification_failed_context_google_analytics_session.json b/tests/Fixtures/organization_domain_verification_failed_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/organization_domain_verification_failed_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/organization_domain_verification_failed_data.json b/tests/Fixtures/organization_domain_verification_failed_data.json new file mode 100644 index 00000000..2a59f149 --- /dev/null +++ b/tests/Fixtures/organization_domain_verification_failed_data.json @@ -0,0 +1,15 @@ +{ + "reason": "domain_verification_period_expired", + "organization_domain": { + "object": "organization_domain", + "id": "org_domain_01EHZNVPK2QXHMVWCEDQEKY69A", + "organization_id": "org_01HE8GSH8FQPASKSY27THRKRBP", + "domain": "foo-corp.com", + "state": "pending", + "verification_prefix": "superapp-domain-verification-z3kjny", + "verification_token": "m5Oztg3jdK4NJLgs8uIlIprMw", + "verification_strategy": "dns", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } +} diff --git a/tests/Fixtures/organization_domain_verification_failed_data_organization_domain.json b/tests/Fixtures/organization_domain_verification_failed_data_organization_domain.json new file mode 100644 index 00000000..9bc0c0a1 --- /dev/null +++ b/tests/Fixtures/organization_domain_verification_failed_data_organization_domain.json @@ -0,0 +1,12 @@ +{ + "object": "organization_domain", + "id": "org_domain_01EHZNVPK2QXHMVWCEDQEKY69A", + "organization_id": "org_01HE8GSH8FQPASKSY27THRKRBP", + "domain": "foo-corp.com", + "state": "pending", + "verification_prefix": "superapp-domain-verification-z3kjny", + "verification_token": "m5Oztg3jdK4NJLgs8uIlIprMw", + "verification_strategy": "dns", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/organization_domain_verified.json b/tests/Fixtures/organization_domain_verified.json new file mode 100644 index 00000000..ec60b317 --- /dev/null +++ b/tests/Fixtures/organization_domain_verified.json @@ -0,0 +1,38 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "organization_domain.verified", + "data": { + "object": "organization_domain", + "id": "org_domain_01EHZNVPK2QXHMVWCEDQEKY69A", + "organization_id": "org_01HE8GSH8FQPASKSY27THRKRBP", + "domain": "foo-corp.com", + "state": "pending", + "verification_prefix": "superapp-domain-verification-z3kjny", + "verification_token": "m5Oztg3jdK4NJLgs8uIlIprMw", + "verification_strategy": "dns", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/organization_domain_verified_context.json b/tests/Fixtures/organization_domain_verified_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/organization_domain_verified_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/organization_domain_verified_context_actor.json b/tests/Fixtures/organization_domain_verified_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/organization_domain_verified_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/organization_domain_verified_context_google_analytics_session.json b/tests/Fixtures/organization_domain_verified_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/organization_domain_verified_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/organization_domain_verified_data.json b/tests/Fixtures/organization_domain_verified_data.json new file mode 100644 index 00000000..9bc0c0a1 --- /dev/null +++ b/tests/Fixtures/organization_domain_verified_data.json @@ -0,0 +1,12 @@ +{ + "object": "organization_domain", + "id": "org_domain_01EHZNVPK2QXHMVWCEDQEKY69A", + "organization_id": "org_01HE8GSH8FQPASKSY27THRKRBP", + "domain": "foo-corp.com", + "state": "pending", + "verification_prefix": "superapp-domain-verification-z3kjny", + "verification_token": "m5Oztg3jdK4NJLgs8uIlIprMw", + "verification_strategy": "dns", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/organization_input.json b/tests/Fixtures/organization_input.json new file mode 100644 index 00000000..374fb083 --- /dev/null +++ b/tests/Fixtures/organization_input.json @@ -0,0 +1,17 @@ +{ + "name": "Foo Corp", + "allow_profiles_outside_organization": false, + "domains": [ + "example.com" + ], + "domain_data": [ + { + "domain": "foo-corp.com", + "state": "verified" + } + ], + "metadata": { + "tier": "diamond" + }, + "external_id": "ext_12345" +} diff --git a/tests/Fixtures/organization_list_list_metadata.json b/tests/Fixtures/organization_list_list_metadata.json new file mode 100644 index 00000000..5c4faed9 --- /dev/null +++ b/tests/Fixtures/organization_list_list_metadata.json @@ -0,0 +1,4 @@ +{ + "before": "org_01HXYZ123456789ABCDEFGHIJ", + "after": "org_01HXYZ987654321KJIHGFEDCBA" +} diff --git a/tests/Fixtures/organization_membership.json b/tests/Fixtures/organization_membership.json new file mode 100644 index 00000000..afc05d1e --- /dev/null +++ b/tests/Fixtures/organization_membership.json @@ -0,0 +1,19 @@ +{ + "object": "organization_membership", + "id": "om_01HXYZ123456789ABCDEFGHIJ", + "user_id": "user_01E4ZCR3C5A4QZ2Z2JQXGKZJ9E", + "organization_id": "org_01E4ZCR3C56J083X43JQXF3JK5", + "status": "active", + "directory_managed": false, + "organization_name": "Acme Corp", + "custom_attributes": { + "department": "Engineering", + "title": "Developer Experience Engineer", + "location": "Brooklyn" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "role": { + "slug": "admin" + } +} diff --git a/tests/Fixtures/organization_membership_created.json b/tests/Fixtures/organization_membership_created.json new file mode 100644 index 00000000..540834a5 --- /dev/null +++ b/tests/Fixtures/organization_membership_created.json @@ -0,0 +1,48 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "organization_membership.created", + "data": { + "object": "organization_membership", + "id": "om_01EHWNCE74X7JSDV0X3SZ3KJNY", + "user_id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "status": "active", + "role": { + "key": {}, + "slug": "admin" + }, + "roles": [ + { + "slug": "admin" + } + ], + "custom_attributes": { + "key": {} + }, + "directory_managed": false, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/organization_membership_created_context.json b/tests/Fixtures/organization_membership_created_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/organization_membership_created_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/organization_membership_created_context_actor.json b/tests/Fixtures/organization_membership_created_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/organization_membership_created_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/organization_membership_created_context_google_analytics_session.json b/tests/Fixtures/organization_membership_created_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/organization_membership_created_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/organization_membership_created_data.json b/tests/Fixtures/organization_membership_created_data.json new file mode 100644 index 00000000..fc15e07c --- /dev/null +++ b/tests/Fixtures/organization_membership_created_data.json @@ -0,0 +1,22 @@ +{ + "object": "organization_membership", + "id": "om_01EHWNCE74X7JSDV0X3SZ3KJNY", + "user_id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "status": "active", + "role": { + "key": {}, + "slug": "admin" + }, + "roles": [ + { + "slug": "admin" + } + ], + "custom_attributes": { + "key": {} + }, + "directory_managed": false, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/organization_membership_deleted.json b/tests/Fixtures/organization_membership_deleted.json new file mode 100644 index 00000000..4e74801d --- /dev/null +++ b/tests/Fixtures/organization_membership_deleted.json @@ -0,0 +1,48 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "organization_membership.deleted", + "data": { + "object": "organization_membership", + "id": "om_01EHWNCE74X7JSDV0X3SZ3KJNY", + "user_id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "status": "active", + "role": { + "key": {}, + "slug": "admin" + }, + "roles": [ + { + "slug": "admin" + } + ], + "custom_attributes": { + "key": {} + }, + "directory_managed": false, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/organization_membership_deleted_context.json b/tests/Fixtures/organization_membership_deleted_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/organization_membership_deleted_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/organization_membership_deleted_context_actor.json b/tests/Fixtures/organization_membership_deleted_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/organization_membership_deleted_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/organization_membership_deleted_context_google_analytics_session.json b/tests/Fixtures/organization_membership_deleted_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/organization_membership_deleted_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/organization_membership_deleted_data.json b/tests/Fixtures/organization_membership_deleted_data.json new file mode 100644 index 00000000..fc15e07c --- /dev/null +++ b/tests/Fixtures/organization_membership_deleted_data.json @@ -0,0 +1,22 @@ +{ + "object": "organization_membership", + "id": "om_01EHWNCE74X7JSDV0X3SZ3KJNY", + "user_id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "status": "active", + "role": { + "key": {}, + "slug": "admin" + }, + "roles": [ + { + "slug": "admin" + } + ], + "custom_attributes": { + "key": {} + }, + "directory_managed": false, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/organization_membership_updated.json b/tests/Fixtures/organization_membership_updated.json new file mode 100644 index 00000000..aab08ba8 --- /dev/null +++ b/tests/Fixtures/organization_membership_updated.json @@ -0,0 +1,48 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "organization_membership.updated", + "data": { + "object": "organization_membership", + "id": "om_01EHWNCE74X7JSDV0X3SZ3KJNY", + "user_id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "status": "active", + "role": { + "key": {}, + "slug": "admin" + }, + "roles": [ + { + "slug": "admin" + } + ], + "custom_attributes": { + "key": {} + }, + "directory_managed": false, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/organization_membership_updated_context.json b/tests/Fixtures/organization_membership_updated_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/organization_membership_updated_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/organization_membership_updated_context_actor.json b/tests/Fixtures/organization_membership_updated_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/organization_membership_updated_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/organization_membership_updated_context_google_analytics_session.json b/tests/Fixtures/organization_membership_updated_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/organization_membership_updated_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/organization_membership_updated_data.json b/tests/Fixtures/organization_membership_updated_data.json new file mode 100644 index 00000000..fc15e07c --- /dev/null +++ b/tests/Fixtures/organization_membership_updated_data.json @@ -0,0 +1,22 @@ +{ + "object": "organization_membership", + "id": "om_01EHWNCE74X7JSDV0X3SZ3KJNY", + "user_id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "status": "active", + "role": { + "key": {}, + "slug": "admin" + }, + "roles": [ + { + "slug": "admin" + } + ], + "custom_attributes": { + "key": {} + }, + "directory_managed": false, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/organization_role_created.json b/tests/Fixtures/organization_role_created.json new file mode 100644 index 00000000..babf5d79 --- /dev/null +++ b/tests/Fixtures/organization_role_created.json @@ -0,0 +1,40 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "organization_role.created", + "data": { + "object": "organization_role", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "slug": "billing-admin", + "name": "Billing Administrator", + "description": "Can manage billing settings.", + "resource_type_slug": "organization", + "permissions": [ + "users:read", + "users:write" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/organization_role_created_context.json b/tests/Fixtures/organization_role_created_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/organization_role_created_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/organization_role_created_context_actor.json b/tests/Fixtures/organization_role_created_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/organization_role_created_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/organization_role_created_context_google_analytics_session.json b/tests/Fixtures/organization_role_created_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/organization_role_created_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/organization_role_created_data.json b/tests/Fixtures/organization_role_created_data.json new file mode 100644 index 00000000..eec94d53 --- /dev/null +++ b/tests/Fixtures/organization_role_created_data.json @@ -0,0 +1,14 @@ +{ + "object": "organization_role", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "slug": "billing-admin", + "name": "Billing Administrator", + "description": "Can manage billing settings.", + "resource_type_slug": "organization", + "permissions": [ + "users:read", + "users:write" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/organization_role_deleted.json b/tests/Fixtures/organization_role_deleted.json new file mode 100644 index 00000000..77a218a1 --- /dev/null +++ b/tests/Fixtures/organization_role_deleted.json @@ -0,0 +1,40 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "organization_role.deleted", + "data": { + "object": "organization_role", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "slug": "billing-admin", + "name": "Billing Administrator", + "description": "Can manage billing settings.", + "resource_type_slug": "organization", + "permissions": [ + "users:read", + "users:write" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/organization_role_deleted_context.json b/tests/Fixtures/organization_role_deleted_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/organization_role_deleted_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/organization_role_deleted_context_actor.json b/tests/Fixtures/organization_role_deleted_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/organization_role_deleted_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/organization_role_deleted_context_google_analytics_session.json b/tests/Fixtures/organization_role_deleted_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/organization_role_deleted_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/organization_role_deleted_data.json b/tests/Fixtures/organization_role_deleted_data.json new file mode 100644 index 00000000..eec94d53 --- /dev/null +++ b/tests/Fixtures/organization_role_deleted_data.json @@ -0,0 +1,14 @@ +{ + "object": "organization_role", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "slug": "billing-admin", + "name": "Billing Administrator", + "description": "Can manage billing settings.", + "resource_type_slug": "organization", + "permissions": [ + "users:read", + "users:write" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/organization_role_updated.json b/tests/Fixtures/organization_role_updated.json new file mode 100644 index 00000000..3a42722e --- /dev/null +++ b/tests/Fixtures/organization_role_updated.json @@ -0,0 +1,40 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "organization_role.updated", + "data": { + "object": "organization_role", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "slug": "billing-admin", + "name": "Billing Administrator", + "description": "Can manage billing settings.", + "resource_type_slug": "organization", + "permissions": [ + "users:read", + "users:write" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/organization_role_updated_context.json b/tests/Fixtures/organization_role_updated_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/organization_role_updated_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/organization_role_updated_context_actor.json b/tests/Fixtures/organization_role_updated_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/organization_role_updated_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/organization_role_updated_context_google_analytics_session.json b/tests/Fixtures/organization_role_updated_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/organization_role_updated_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/organization_role_updated_data.json b/tests/Fixtures/organization_role_updated_data.json new file mode 100644 index 00000000..eec94d53 --- /dev/null +++ b/tests/Fixtures/organization_role_updated_data.json @@ -0,0 +1,14 @@ +{ + "object": "organization_role", + "organization_id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "slug": "billing-admin", + "name": "Billing Administrator", + "description": "Can manage billing settings.", + "resource_type_slug": "organization", + "permissions": [ + "users:read", + "users:write" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/organization_selection_session_authenticate_request.json b/tests/Fixtures/organization_selection_session_authenticate_request.json new file mode 100644 index 00000000..7d0fb2f3 --- /dev/null +++ b/tests/Fixtures/organization_selection_session_authenticate_request.json @@ -0,0 +1,10 @@ +{ + "client_id": "client_01HXYZ123456789ABCDEFGHIJ", + "client_secret": "sk_test_....", + "grant_type": "urn:workos:oauth:grant-type:organization-selection", + "pending_authentication_token": "cTDQJTTkTkkVYxbn...", + "organization_id": "org_01EHQMYV6MBK39QC5PZXHY59C3", + "ip_address": "203.0.113.42", + "device_id": "device_01HXYZ123456789ABCDEFGHIJ", + "user_agent": "Mozilla/5.0" +} diff --git a/tests/Fixtures/organization_updated.json b/tests/Fixtures/organization_updated.json new file mode 100644 index 00000000..5c5cf506 --- /dev/null +++ b/tests/Fixtures/organization_updated.json @@ -0,0 +1,52 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "organization.updated", + "data": { + "object": "organization", + "id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "name": "Acme Inc.", + "domains": [ + { + "object": "organization_domain", + "id": "org_domain_01EHZNVPK2QXHMVWCEDQEKY69A", + "organization_id": "org_01HE8GSH8FQPASKSY27THRKRBP", + "domain": "foo-corp.com", + "state": "pending", + "verification_prefix": "superapp-domain-verification-z3kjny", + "verification_token": "m5Oztg3jdK4NJLgs8uIlIprMw", + "verification_strategy": "dns", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + ], + "metadata": { + "tier": "diamond" + }, + "external_id": "2fe01467-f7ea-4dd2-8b79-c2b4f56d0191", + "stripe_customer_id": "cus_R9qWAGMQ6nGE7V", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/organization_updated_context.json b/tests/Fixtures/organization_updated_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/organization_updated_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/organization_updated_context_actor.json b/tests/Fixtures/organization_updated_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/organization_updated_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/organization_updated_context_google_analytics_session.json b/tests/Fixtures/organization_updated_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/organization_updated_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/organization_updated_data.json b/tests/Fixtures/organization_updated_data.json new file mode 100644 index 00000000..71f863b4 --- /dev/null +++ b/tests/Fixtures/organization_updated_data.json @@ -0,0 +1,26 @@ +{ + "object": "organization", + "id": "org_01EHWNCE74X7JSDV0X3SZ3KJNY", + "name": "Acme Inc.", + "domains": [ + { + "object": "organization_domain", + "id": "org_domain_01EHZNVPK2QXHMVWCEDQEKY69A", + "organization_id": "org_01HE8GSH8FQPASKSY27THRKRBP", + "domain": "foo-corp.com", + "state": "pending", + "verification_prefix": "superapp-domain-verification-z3kjny", + "verification_token": "m5Oztg3jdK4NJLgs8uIlIprMw", + "verification_strategy": "dns", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + ], + "metadata": { + "tier": "diamond" + }, + "external_id": "2fe01467-f7ea-4dd2-8b79-c2b4f56d0191", + "stripe_customer_id": "cus_R9qWAGMQ6nGE7V", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/organization_updated_data_domain.json b/tests/Fixtures/organization_updated_data_domain.json new file mode 100644 index 00000000..9bc0c0a1 --- /dev/null +++ b/tests/Fixtures/organization_updated_data_domain.json @@ -0,0 +1,12 @@ +{ + "object": "organization_domain", + "id": "org_domain_01EHZNVPK2QXHMVWCEDQEKY69A", + "organization_id": "org_01HE8GSH8FQPASKSY27THRKRBP", + "domain": "foo-corp.com", + "state": "pending", + "verification_prefix": "superapp-domain-verification-z3kjny", + "verification_token": "m5Oztg3jdK4NJLgs8uIlIprMw", + "verification_strategy": "dns", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/password_reset.json b/tests/Fixtures/password_reset.json new file mode 100644 index 00000000..d27b794f --- /dev/null +++ b/tests/Fixtures/password_reset.json @@ -0,0 +1,10 @@ +{ + "object": "password_reset", + "id": "password_reset_01E4ZCR3C56J083X43JQXF3JK5", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "marcelina.davis@example.com", + "expires_at": "2026-01-15T12:00:00.000Z", + "created_at": "2026-01-15T12:00:00.000Z", + "password_reset_token": "Z1uX3RbwcIl5fIGJJJCXXisdI", + "password_reset_url": "https://your-app.com/reset-password?token=Z1uX3RbwcIl5fIGJJJCXXisdI" +} diff --git a/tests/Fixtures/password_reset_created.json b/tests/Fixtures/password_reset_created.json new file mode 100644 index 00000000..ebf89e30 --- /dev/null +++ b/tests/Fixtures/password_reset_created.json @@ -0,0 +1,34 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "password_reset.created", + "data": { + "object": "password_reset", + "id": "password_reset_01E4ZCR3C56J083X43JQXF3JK5", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "marcelina.davis@example.com", + "expires_at": "2026-01-15T12:00:00.000Z", + "created_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/password_reset_created_context.json b/tests/Fixtures/password_reset_created_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/password_reset_created_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/password_reset_created_context_actor.json b/tests/Fixtures/password_reset_created_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/password_reset_created_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/password_reset_created_context_google_analytics_session.json b/tests/Fixtures/password_reset_created_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/password_reset_created_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/password_reset_created_data.json b/tests/Fixtures/password_reset_created_data.json new file mode 100644 index 00000000..7fe0704a --- /dev/null +++ b/tests/Fixtures/password_reset_created_data.json @@ -0,0 +1,8 @@ +{ + "object": "password_reset", + "id": "password_reset_01E4ZCR3C56J083X43JQXF3JK5", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "marcelina.davis@example.com", + "expires_at": "2026-01-15T12:00:00.000Z", + "created_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/password_reset_succeeded.json b/tests/Fixtures/password_reset_succeeded.json new file mode 100644 index 00000000..93154db4 --- /dev/null +++ b/tests/Fixtures/password_reset_succeeded.json @@ -0,0 +1,34 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "password_reset.succeeded", + "data": { + "object": "password_reset", + "id": "password_reset_01E4ZCR3C56J083X43JQXF3JK5", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "marcelina.davis@example.com", + "expires_at": "2026-01-15T12:00:00.000Z", + "created_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/password_reset_succeeded_context.json b/tests/Fixtures/password_reset_succeeded_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/password_reset_succeeded_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/password_reset_succeeded_context_actor.json b/tests/Fixtures/password_reset_succeeded_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/password_reset_succeeded_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/password_reset_succeeded_context_google_analytics_session.json b/tests/Fixtures/password_reset_succeeded_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/password_reset_succeeded_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/password_reset_succeeded_data.json b/tests/Fixtures/password_reset_succeeded_data.json new file mode 100644 index 00000000..7fe0704a --- /dev/null +++ b/tests/Fixtures/password_reset_succeeded_data.json @@ -0,0 +1,8 @@ +{ + "object": "password_reset", + "id": "password_reset_01E4ZCR3C56J083X43JQXF3JK5", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "email": "marcelina.davis@example.com", + "expires_at": "2026-01-15T12:00:00.000Z", + "created_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/password_session_authenticate_request.json b/tests/Fixtures/password_session_authenticate_request.json new file mode 100644 index 00000000..ea240764 --- /dev/null +++ b/tests/Fixtures/password_session_authenticate_request.json @@ -0,0 +1,11 @@ +{ + "client_id": "client_01HXYZ123456789ABCDEFGHIJ", + "client_secret": "sk_test_....", + "grant_type": "password", + "email": "user@example.com", + "password": "strong_password_123!", + "invitation_token": "inv_tok_01HXYZ123456789ABCDEFGHIJ", + "ip_address": "203.0.113.42", + "device_id": "device_01HXYZ123456789ABCDEFGHIJ", + "user_agent": "Mozilla/5.0" +} diff --git a/tests/Fixtures/permission.json b/tests/Fixtures/permission.json new file mode 100644 index 00000000..e4ac8b82 --- /dev/null +++ b/tests/Fixtures/permission.json @@ -0,0 +1,11 @@ +{ + "object": "permission", + "id": "perm_01HXYZ123456789ABCDEFGHIJ", + "slug": "documents:read", + "name": "View Documents", + "description": "Allows viewing document contents", + "system": false, + "resource_type_slug": "document", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/permission_created.json b/tests/Fixtures/permission_created.json new file mode 100644 index 00000000..d3b7d142 --- /dev/null +++ b/tests/Fixtures/permission_created.json @@ -0,0 +1,36 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "permission.created", + "data": { + "object": "permission", + "id": "perm_01EHWNCE74X7JSDV0X3SZ3KJNY", + "slug": "billing:manage", + "name": "Manage Billing", + "description": "Allows managing billing settings.", + "system": false, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/permission_created_context.json b/tests/Fixtures/permission_created_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/permission_created_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/permission_created_context_actor.json b/tests/Fixtures/permission_created_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/permission_created_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/permission_created_context_google_analytics_session.json b/tests/Fixtures/permission_created_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/permission_created_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/permission_created_data.json b/tests/Fixtures/permission_created_data.json new file mode 100644 index 00000000..b17cbcbe --- /dev/null +++ b/tests/Fixtures/permission_created_data.json @@ -0,0 +1,10 @@ +{ + "object": "permission", + "id": "perm_01EHWNCE74X7JSDV0X3SZ3KJNY", + "slug": "billing:manage", + "name": "Manage Billing", + "description": "Allows managing billing settings.", + "system": false, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/permission_deleted.json b/tests/Fixtures/permission_deleted.json new file mode 100644 index 00000000..89956adc --- /dev/null +++ b/tests/Fixtures/permission_deleted.json @@ -0,0 +1,36 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "permission.deleted", + "data": { + "object": "permission", + "id": "perm_01EHWNCE74X7JSDV0X3SZ3KJNY", + "slug": "billing:manage", + "name": "Manage Billing", + "description": "Allows managing billing settings.", + "system": false, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/permission_deleted_context.json b/tests/Fixtures/permission_deleted_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/permission_deleted_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/permission_deleted_context_actor.json b/tests/Fixtures/permission_deleted_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/permission_deleted_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/permission_deleted_context_google_analytics_session.json b/tests/Fixtures/permission_deleted_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/permission_deleted_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/permission_deleted_data.json b/tests/Fixtures/permission_deleted_data.json new file mode 100644 index 00000000..b17cbcbe --- /dev/null +++ b/tests/Fixtures/permission_deleted_data.json @@ -0,0 +1,10 @@ +{ + "object": "permission", + "id": "perm_01EHWNCE74X7JSDV0X3SZ3KJNY", + "slug": "billing:manage", + "name": "Manage Billing", + "description": "Allows managing billing settings.", + "system": false, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/permission_updated.json b/tests/Fixtures/permission_updated.json new file mode 100644 index 00000000..4b5fa285 --- /dev/null +++ b/tests/Fixtures/permission_updated.json @@ -0,0 +1,36 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "permission.updated", + "data": { + "object": "permission", + "id": "perm_01EHWNCE74X7JSDV0X3SZ3KJNY", + "slug": "billing:manage", + "name": "Manage Billing", + "description": "Allows managing billing settings.", + "system": false, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/permission_updated_context.json b/tests/Fixtures/permission_updated_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/permission_updated_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/permission_updated_context_actor.json b/tests/Fixtures/permission_updated_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/permission_updated_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/permission_updated_context_google_analytics_session.json b/tests/Fixtures/permission_updated_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/permission_updated_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/permission_updated_data.json b/tests/Fixtures/permission_updated_data.json new file mode 100644 index 00000000..b17cbcbe --- /dev/null +++ b/tests/Fixtures/permission_updated_data.json @@ -0,0 +1,10 @@ +{ + "object": "permission", + "id": "perm_01EHWNCE74X7JSDV0X3SZ3KJNY", + "slug": "billing:manage", + "name": "Manage Billing", + "description": "Allows managing billing settings.", + "system": false, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/portal_link_response.json b/tests/Fixtures/portal_link_response.json new file mode 100644 index 00000000..811f32a9 --- /dev/null +++ b/tests/Fixtures/portal_link_response.json @@ -0,0 +1,3 @@ +{ + "link": "https://setup.workos.com?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." +} diff --git a/tests/Fixtures/profile.json b/tests/Fixtures/profile.json new file mode 100644 index 00000000..485a13ce --- /dev/null +++ b/tests/Fixtures/profile.json @@ -0,0 +1,29 @@ +{ + "object": "profile", + "id": "prof_01DMC79VCBZ0NY2099737PSVF1", + "organization_id": "org_01EHQMYV6MBK39QC5PZXHY59C3", + "connection_id": "conn_01E4ZCR3C56J083X43JQXF3JK5", + "connection_type": "GoogleOAuth", + "idp_id": "103456789012345678901", + "email": "todd@example.com", + "first_name": "Todd", + "last_name": "Rundgren", + "role": { + "slug": "admin" + }, + "roles": [ + { + "slug": "admin" + } + ], + "groups": [ + "Engineering", + "Admins" + ], + "custom_attributes": { + "key": {} + }, + "raw_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/radar_list_entry_already_present_response.json b/tests/Fixtures/radar_list_entry_already_present_response.json new file mode 100644 index 00000000..d20390c3 --- /dev/null +++ b/tests/Fixtures/radar_list_entry_already_present_response.json @@ -0,0 +1,3 @@ +{ + "message": "Entry already present in list" +} diff --git a/tests/Fixtures/radar_standalone_assess_request.json b/tests/Fixtures/radar_standalone_assess_request.json new file mode 100644 index 00000000..6f3673e8 --- /dev/null +++ b/tests/Fixtures/radar_standalone_assess_request.json @@ -0,0 +1,9 @@ +{ + "ip_address": "49.78.240.97", + "user_agent": "Mozilla/5.0", + "email": "user@example.com", + "auth_method": "Password", + "action": "login", + "device_fingerprint": "fp_abc123", + "bot_score": "0.1" +} diff --git a/tests/Fixtures/radar_standalone_delete_radar_list_entry_request.json b/tests/Fixtures/radar_standalone_delete_radar_list_entry_request.json new file mode 100644 index 00000000..a123eb26 --- /dev/null +++ b/tests/Fixtures/radar_standalone_delete_radar_list_entry_request.json @@ -0,0 +1,3 @@ +{ + "entry": "198.51.100.42" +} diff --git a/tests/Fixtures/radar_standalone_response.json b/tests/Fixtures/radar_standalone_response.json new file mode 100644 index 00000000..1670848e --- /dev/null +++ b/tests/Fixtures/radar_standalone_response.json @@ -0,0 +1,7 @@ +{ + "verdict": "block", + "reason": "Detected enabled Radar control", + "attempt_id": "radar_att_01HZBC6N1EB1ZY7KG32X", + "control": "bot_detection", + "blocklist_type": "ip_address" +} diff --git a/tests/Fixtures/radar_standalone_update_radar_attempt_request.json b/tests/Fixtures/radar_standalone_update_radar_attempt_request.json new file mode 100644 index 00000000..b9598708 --- /dev/null +++ b/tests/Fixtures/radar_standalone_update_radar_attempt_request.json @@ -0,0 +1,4 @@ +{ + "challenge_status": "success", + "attempt_status": "success" +} diff --git a/tests/Fixtures/radar_standalone_update_radar_list_request.json b/tests/Fixtures/radar_standalone_update_radar_list_request.json new file mode 100644 index 00000000..a123eb26 --- /dev/null +++ b/tests/Fixtures/radar_standalone_update_radar_list_request.json @@ -0,0 +1,3 @@ +{ + "entry": "198.51.100.42" +} diff --git a/tests/Fixtures/redirect_uri.json b/tests/Fixtures/redirect_uri.json new file mode 100644 index 00000000..dcd6ad8d --- /dev/null +++ b/tests/Fixtures/redirect_uri.json @@ -0,0 +1,8 @@ +{ + "object": "redirect_uri", + "id": "ruri_01EHZNVPK3SFK441A1RGBFSHRT", + "uri": "https://example.com/callback", + "default": true, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/redirect_uri_input.json b/tests/Fixtures/redirect_uri_input.json new file mode 100644 index 00000000..083dd6a8 --- /dev/null +++ b/tests/Fixtures/redirect_uri_input.json @@ -0,0 +1,4 @@ +{ + "uri": "https://example.com/callback", + "default": true +} diff --git a/tests/Fixtures/refresh_token_session_authenticate_request.json b/tests/Fixtures/refresh_token_session_authenticate_request.json new file mode 100644 index 00000000..6acead44 --- /dev/null +++ b/tests/Fixtures/refresh_token_session_authenticate_request.json @@ -0,0 +1,10 @@ +{ + "client_id": "client_01HXYZ123456789ABCDEFGHIJ", + "client_secret": "sk_test_....", + "grant_type": "refresh_token", + "refresh_token": "yAjhKk23hJMM3DaR...", + "organization_id": "org_01EHQMYV6MBK39QC5PZXHY59C3", + "ip_address": "203.0.113.42", + "device_id": "device_01HXYZ123456789ABCDEFGHIJ", + "user_agent": "Mozilla/5.0" +} diff --git a/tests/Fixtures/remove_role.json b/tests/Fixtures/remove_role.json new file mode 100644 index 00000000..f69fda37 --- /dev/null +++ b/tests/Fixtures/remove_role.json @@ -0,0 +1,6 @@ +{ + "role_slug": "editor", + "resource_id": "authz_resource_01HXYZ123456789ABCDEFGH", + "resource_external_id": "external_01HXYZ123456789ABCDEFGH", + "resource_type_slug": "project" +} diff --git a/tests/Fixtures/resend_user_invite_options.json b/tests/Fixtures/resend_user_invite_options.json new file mode 100644 index 00000000..d160103c --- /dev/null +++ b/tests/Fixtures/resend_user_invite_options.json @@ -0,0 +1,3 @@ +{ + "locale": "en" +} diff --git a/tests/Fixtures/reset_password_response.json b/tests/Fixtures/reset_password_response.json new file mode 100644 index 00000000..647d4c25 --- /dev/null +++ b/tests/Fixtures/reset_password_response.json @@ -0,0 +1,19 @@ +{ + "user": { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": true, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": { + "timezone": "America/New_York" + }, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } +} diff --git a/tests/Fixtures/revoke_session.json b/tests/Fixtures/revoke_session.json new file mode 100644 index 00000000..c1d3e07f --- /dev/null +++ b/tests/Fixtures/revoke_session.json @@ -0,0 +1,4 @@ +{ + "session_id": "session_01H93ZY4F80QPBEZ1R5B2SHQG8", + "return_to": "https://example.com" +} diff --git a/tests/Fixtures/role.json b/tests/Fixtures/role.json new file mode 100644 index 00000000..cb6a9236 --- /dev/null +++ b/tests/Fixtures/role.json @@ -0,0 +1,15 @@ +{ + "slug": "admin", + "object": "role", + "id": "role_01EHQMYV6MBK39QC5PZXHY59C3", + "name": "Admin", + "description": "Can manage all resources", + "type": "EnvironmentRole", + "resource_type_slug": "organization", + "permissions": [ + "posts:read", + "posts:write" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/role_assignment.json b/tests/Fixtures/role_assignment.json new file mode 100644 index 00000000..4979ca1b --- /dev/null +++ b/tests/Fixtures/role_assignment.json @@ -0,0 +1,14 @@ +{ + "object": "role_assignment", + "id": "role_assignment_01HXYZ123456789ABCDEFGH", + "role": { + "slug": "admin" + }, + "resource": { + "id": "authz_resource_01HXYZ123456789ABCDEFGH", + "external_id": "proj-456", + "resource_type_slug": "project" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/role_assignment_list_list_metadata.json b/tests/Fixtures/role_assignment_list_list_metadata.json new file mode 100644 index 00000000..fc7cce46 --- /dev/null +++ b/tests/Fixtures/role_assignment_list_list_metadata.json @@ -0,0 +1,4 @@ +{ + "before": "role_assignment_01HXYZ123456789ABCDEFGHIJ", + "after": "role_assignment_01HXYZ987654321KJIHGFEDCBA" +} diff --git a/tests/Fixtures/role_assignment_resource.json b/tests/Fixtures/role_assignment_resource.json new file mode 100644 index 00000000..53f9d508 --- /dev/null +++ b/tests/Fixtures/role_assignment_resource.json @@ -0,0 +1,5 @@ +{ + "id": "authz_resource_01HXYZ123456789ABCDEFGH", + "external_id": "proj-456", + "resource_type_slug": "project" +} diff --git a/tests/Fixtures/role_created.json b/tests/Fixtures/role_created.json new file mode 100644 index 00000000..6aec0ba9 --- /dev/null +++ b/tests/Fixtures/role_created.json @@ -0,0 +1,37 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "role.created", + "data": { + "object": "role", + "slug": "admin", + "resource_type_slug": "organization", + "permissions": [ + "users:read", + "users:write" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/role_created_context.json b/tests/Fixtures/role_created_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/role_created_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/role_created_context_actor.json b/tests/Fixtures/role_created_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/role_created_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/role_created_context_google_analytics_session.json b/tests/Fixtures/role_created_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/role_created_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/role_created_data.json b/tests/Fixtures/role_created_data.json new file mode 100644 index 00000000..37493fb0 --- /dev/null +++ b/tests/Fixtures/role_created_data.json @@ -0,0 +1,11 @@ +{ + "object": "role", + "slug": "admin", + "resource_type_slug": "organization", + "permissions": [ + "users:read", + "users:write" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/role_deleted.json b/tests/Fixtures/role_deleted.json new file mode 100644 index 00000000..d5e48309 --- /dev/null +++ b/tests/Fixtures/role_deleted.json @@ -0,0 +1,37 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "role.deleted", + "data": { + "object": "role", + "slug": "admin", + "resource_type_slug": "organization", + "permissions": [ + "users:read", + "users:write" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/role_deleted_context.json b/tests/Fixtures/role_deleted_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/role_deleted_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/role_deleted_context_actor.json b/tests/Fixtures/role_deleted_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/role_deleted_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/role_deleted_context_google_analytics_session.json b/tests/Fixtures/role_deleted_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/role_deleted_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/role_deleted_data.json b/tests/Fixtures/role_deleted_data.json new file mode 100644 index 00000000..37493fb0 --- /dev/null +++ b/tests/Fixtures/role_deleted_data.json @@ -0,0 +1,11 @@ +{ + "object": "role", + "slug": "admin", + "resource_type_slug": "organization", + "permissions": [ + "users:read", + "users:write" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/role_list.json b/tests/Fixtures/role_list.json new file mode 100644 index 00000000..424fd096 --- /dev/null +++ b/tests/Fixtures/role_list.json @@ -0,0 +1,20 @@ +{ + "object": "list", + "data": [ + { + "slug": "admin", + "object": "role", + "id": "role_01EHQMYV6MBK39QC5PZXHY59C3", + "name": "Admin", + "description": "Can manage all resources", + "type": "EnvironmentRole", + "resource_type_slug": "organization", + "permissions": [ + "posts:read", + "posts:write" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } + ] +} diff --git a/tests/Fixtures/role_updated.json b/tests/Fixtures/role_updated.json new file mode 100644 index 00000000..575f4513 --- /dev/null +++ b/tests/Fixtures/role_updated.json @@ -0,0 +1,37 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "role.updated", + "data": { + "object": "role", + "slug": "admin", + "resource_type_slug": "organization", + "permissions": [ + "users:read", + "users:write" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/role_updated_context.json b/tests/Fixtures/role_updated_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/role_updated_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/role_updated_context_actor.json b/tests/Fixtures/role_updated_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/role_updated_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/role_updated_context_google_analytics_session.json b/tests/Fixtures/role_updated_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/role_updated_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/role_updated_data.json b/tests/Fixtures/role_updated_data.json new file mode 100644 index 00000000..37493fb0 --- /dev/null +++ b/tests/Fixtures/role_updated_data.json @@ -0,0 +1,11 @@ +{ + "object": "role", + "slug": "admin", + "resource_type_slug": "organization", + "permissions": [ + "users:read", + "users:write" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/send_email_change.json b/tests/Fixtures/send_email_change.json new file mode 100644 index 00000000..b34dae4f --- /dev/null +++ b/tests/Fixtures/send_email_change.json @@ -0,0 +1,3 @@ +{ + "new_email": "new.email@example.com" +} diff --git a/tests/Fixtures/send_verification_email_response.json b/tests/Fixtures/send_verification_email_response.json new file mode 100644 index 00000000..647d4c25 --- /dev/null +++ b/tests/Fixtures/send_verification_email_response.json @@ -0,0 +1,19 @@ +{ + "user": { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": true, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": { + "timezone": "America/New_York" + }, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } +} diff --git a/tests/Fixtures/session_created.json b/tests/Fixtures/session_created.json new file mode 100644 index 00000000..e21f6b79 --- /dev/null +++ b/tests/Fixtures/session_created.json @@ -0,0 +1,44 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "session.created", + "data": { + "object": "session", + "id": "session_01H93ZY4F80QPBEZ1R5B2SHQG8", + "impersonator": { + "email": "admin@foocorp.com", + "reason": "Investigating an issue with the customer's account." + }, + "ip_address": "198.51.100.42", + "organization_id": "org_01H945H0YD4F97JN9MATX7BYAG", + "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "auth_method": "sso", + "status": "active", + "expires_at": "2026-01-15T12:00:00.000Z", + "ended_at": null, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/session_created_context.json b/tests/Fixtures/session_created_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/session_created_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/session_created_context_actor.json b/tests/Fixtures/session_created_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/session_created_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/session_created_context_google_analytics_session.json b/tests/Fixtures/session_created_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/session_created_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/session_created_data.json b/tests/Fixtures/session_created_data.json new file mode 100644 index 00000000..233ec56a --- /dev/null +++ b/tests/Fixtures/session_created_data.json @@ -0,0 +1,18 @@ +{ + "object": "session", + "id": "session_01H93ZY4F80QPBEZ1R5B2SHQG8", + "impersonator": { + "email": "admin@foocorp.com", + "reason": "Investigating an issue with the customer's account." + }, + "ip_address": "198.51.100.42", + "organization_id": "org_01H945H0YD4F97JN9MATX7BYAG", + "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "auth_method": "sso", + "status": "active", + "expires_at": "2026-01-15T12:00:00.000Z", + "ended_at": null, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/session_created_data_impersonator.json b/tests/Fixtures/session_created_data_impersonator.json new file mode 100644 index 00000000..b483e3f0 --- /dev/null +++ b/tests/Fixtures/session_created_data_impersonator.json @@ -0,0 +1,4 @@ +{ + "email": "admin@foocorp.com", + "reason": "Investigating an issue with the customer's account." +} diff --git a/tests/Fixtures/session_revoked.json b/tests/Fixtures/session_revoked.json new file mode 100644 index 00000000..4234650e --- /dev/null +++ b/tests/Fixtures/session_revoked.json @@ -0,0 +1,44 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "session.revoked", + "data": { + "object": "session", + "id": "session_01H93ZY4F80QPBEZ1R5B2SHQG8", + "impersonator": { + "email": "admin@foocorp.com", + "reason": "Investigating an issue with the customer's account." + }, + "ip_address": "198.51.100.42", + "organization_id": "org_01H945H0YD4F97JN9MATX7BYAG", + "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "auth_method": "sso", + "status": "active", + "expires_at": "2026-01-15T12:00:00.000Z", + "ended_at": null, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/session_revoked_context.json b/tests/Fixtures/session_revoked_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/session_revoked_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/session_revoked_context_actor.json b/tests/Fixtures/session_revoked_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/session_revoked_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/session_revoked_context_google_analytics_session.json b/tests/Fixtures/session_revoked_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/session_revoked_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/session_revoked_data.json b/tests/Fixtures/session_revoked_data.json new file mode 100644 index 00000000..233ec56a --- /dev/null +++ b/tests/Fixtures/session_revoked_data.json @@ -0,0 +1,18 @@ +{ + "object": "session", + "id": "session_01H93ZY4F80QPBEZ1R5B2SHQG8", + "impersonator": { + "email": "admin@foocorp.com", + "reason": "Investigating an issue with the customer's account." + }, + "ip_address": "198.51.100.42", + "organization_id": "org_01H945H0YD4F97JN9MATX7BYAG", + "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "auth_method": "sso", + "status": "active", + "expires_at": "2026-01-15T12:00:00.000Z", + "ended_at": null, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/session_revoked_data_impersonator.json b/tests/Fixtures/session_revoked_data_impersonator.json new file mode 100644 index 00000000..b483e3f0 --- /dev/null +++ b/tests/Fixtures/session_revoked_data_impersonator.json @@ -0,0 +1,4 @@ +{ + "email": "admin@foocorp.com", + "reason": "Investigating an issue with the customer's account." +} diff --git a/tests/Fixtures/set_role_permissions.json b/tests/Fixtures/set_role_permissions.json new file mode 100644 index 00000000..52910b36 --- /dev/null +++ b/tests/Fixtures/set_role_permissions.json @@ -0,0 +1,8 @@ +{ + "permissions": [ + "billing:read", + "billing:write", + "invoices:manage", + "reports:view" + ] +} diff --git a/tests/Fixtures/slim_role.json b/tests/Fixtures/slim_role.json new file mode 100644 index 00000000..21f8f041 --- /dev/null +++ b/tests/Fixtures/slim_role.json @@ -0,0 +1,3 @@ +{ + "slug": "admin" +} diff --git a/tests/Fixtures/sso_authorize_url_response.json b/tests/Fixtures/sso_authorize_url_response.json new file mode 100644 index 00000000..918b2b81 --- /dev/null +++ b/tests/Fixtures/sso_authorize_url_response.json @@ -0,0 +1,3 @@ +{ + "url": "https://accounts.google.com/o/oauth2/v2/auth?client_id=example&redirect_uri=https%3A%2F%2Fapi.workos.com%2Fsso%2Fcallback&response_type=code&scope=openid%20profile%20email" +} diff --git a/tests/Fixtures/sso_device_authorization_request.json b/tests/Fixtures/sso_device_authorization_request.json new file mode 100644 index 00000000..dffd0532 --- /dev/null +++ b/tests/Fixtures/sso_device_authorization_request.json @@ -0,0 +1,3 @@ +{ + "client_id": "client_01HZBC6N1EB1ZY7KG32X" +} diff --git a/tests/Fixtures/sso_intent_options.json b/tests/Fixtures/sso_intent_options.json new file mode 100644 index 00000000..79ab315e --- /dev/null +++ b/tests/Fixtures/sso_intent_options.json @@ -0,0 +1,4 @@ +{ + "bookmark_slug": "chatgpt", + "provider_type": "GoogleSAML" +} diff --git a/tests/Fixtures/sso_logout_authorize_request.json b/tests/Fixtures/sso_logout_authorize_request.json new file mode 100644 index 00000000..80a3c6e7 --- /dev/null +++ b/tests/Fixtures/sso_logout_authorize_request.json @@ -0,0 +1,3 @@ +{ + "profile_id": "prof_01HXYZ123456789ABCDEFGHIJ" +} diff --git a/tests/Fixtures/sso_logout_authorize_response.json b/tests/Fixtures/sso_logout_authorize_response.json new file mode 100644 index 00000000..e4b79225 --- /dev/null +++ b/tests/Fixtures/sso_logout_authorize_response.json @@ -0,0 +1,4 @@ +{ + "logout_url": "https://auth.workos.com/sso/logout?token=eyJhbGciOiJSUzI1NiJ9", + "logout_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwcm9maWxlX2lkIjoicHJvZl8wMUdXUTFHMEgyRk02QVNFRjBIUzEzSENXOS0zMDRrZzAzZyIsImV4cCI6IjE1MTYyMzkwMjIifQ.Wru9Qlnf5DpohtGCKhZU4cVOd3zpiu7QQ-XEX--5A_4" +} diff --git a/tests/Fixtures/sso_token_response.json b/tests/Fixtures/sso_token_response.json new file mode 100644 index 00000000..757c3fb1 --- /dev/null +++ b/tests/Fixtures/sso_token_response.json @@ -0,0 +1,45 @@ +{ + "token_type": "Bearer", + "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6InNzby...", + "expires_in": 600, + "profile": { + "object": "profile", + "id": "prof_01DMC79VCBZ0NY2099737PSVF1", + "organization_id": "org_01EHQMYV6MBK39QC5PZXHY59C3", + "connection_id": "conn_01E4ZCR3C56J083X43JQXF3JK5", + "connection_type": "GoogleOAuth", + "idp_id": "103456789012345678901", + "email": "todd@example.com", + "first_name": "Todd", + "last_name": "Rundgren", + "role": { + "slug": "admin" + }, + "roles": [ + { + "slug": "admin" + } + ], + "groups": [ + "Engineering", + "Admins" + ], + "custom_attributes": { + "key": {} + }, + "raw_attributes": { + "key": {} + } + }, + "oauth_tokens": { + "provider": "GoogleOAuth", + "refresh_token": "1//04g...", + "access_token": "ya29.a0ARrdaM...", + "expires_at": 1735141800, + "scopes": [ + "profile", + "email", + "openid" + ] + } +} diff --git a/tests/Fixtures/sso_token_response_oauth_token.json b/tests/Fixtures/sso_token_response_oauth_token.json new file mode 100644 index 00000000..014b78c6 --- /dev/null +++ b/tests/Fixtures/sso_token_response_oauth_token.json @@ -0,0 +1,11 @@ +{ + "provider": "GoogleOAuth", + "refresh_token": "1//04g...", + "access_token": "ya29.a0ARrdaM...", + "expires_at": 1735141800, + "scopes": [ + "profile", + "email", + "openid" + ] +} diff --git a/tests/Fixtures/token_query.json b/tests/Fixtures/token_query.json new file mode 100644 index 00000000..1051d0d8 --- /dev/null +++ b/tests/Fixtures/token_query.json @@ -0,0 +1,6 @@ +{ + "client_id": "client_01HZBC6N1EB1ZY7KG32X", + "client_secret": "sk_example_123456789", + "code": "authorization_code_value", + "grant_type": "authorization_code" +} diff --git a/tests/Fixtures/update_audit_logs_retention.json b/tests/Fixtures/update_audit_logs_retention.json new file mode 100644 index 00000000..0720427e --- /dev/null +++ b/tests/Fixtures/update_audit_logs_retention.json @@ -0,0 +1,3 @@ +{ + "retention_period_in_days": 30 +} diff --git a/tests/Fixtures/update_authorization_permission.json b/tests/Fixtures/update_authorization_permission.json new file mode 100644 index 00000000..5aed776b --- /dev/null +++ b/tests/Fixtures/update_authorization_permission.json @@ -0,0 +1,4 @@ +{ + "name": "View Documents", + "description": "Allows viewing document contents" +} diff --git a/tests/Fixtures/update_authorization_resource.json b/tests/Fixtures/update_authorization_resource.json new file mode 100644 index 00000000..176a8025 --- /dev/null +++ b/tests/Fixtures/update_authorization_resource.json @@ -0,0 +1,7 @@ +{ + "name": "Updated Name", + "description": "Updated description", + "parent_resource_id": "authz_resource_01HXYZ123456789ABCDEFGHIJ", + "parent_resource_external_id": "parent-workspace-01", + "parent_resource_type_slug": "workspace" +} diff --git a/tests/Fixtures/update_jwt_template.json b/tests/Fixtures/update_jwt_template.json new file mode 100644 index 00000000..bb613667 --- /dev/null +++ b/tests/Fixtures/update_jwt_template.json @@ -0,0 +1,3 @@ +{ + "content": "{\"iss\": \"{{environment.id}}\", \"sub\": \"{{user.id}}\"}" +} diff --git a/tests/Fixtures/update_oauth_application.json b/tests/Fixtures/update_oauth_application.json new file mode 100644 index 00000000..24005a39 --- /dev/null +++ b/tests/Fixtures/update_oauth_application.json @@ -0,0 +1,15 @@ +{ + "name": "My Application", + "description": "An application for managing user access", + "scopes": [ + "openid", + "profile", + "email" + ], + "redirect_uris": [ + { + "uri": "https://example.com/callback", + "default": true + } + ] +} diff --git a/tests/Fixtures/update_organization.json b/tests/Fixtures/update_organization.json new file mode 100644 index 00000000..3e74efde --- /dev/null +++ b/tests/Fixtures/update_organization.json @@ -0,0 +1,18 @@ +{ + "name": "Foo Corp", + "allow_profiles_outside_organization": false, + "domains": [ + "foo-corp.com" + ], + "domain_data": [ + { + "domain": "foo-corp.com", + "state": "verified" + } + ], + "stripe_customer_id": "cus_R9qWAGMQ6nGE7V", + "metadata": { + "tier": "diamond" + }, + "external_id": "2fe01467-f7ea-4dd2-8b79-c2b4f56d0191" +} diff --git a/tests/Fixtures/update_organization_role.json b/tests/Fixtures/update_organization_role.json new file mode 100644 index 00000000..416ea3d1 --- /dev/null +++ b/tests/Fixtures/update_organization_role.json @@ -0,0 +1,4 @@ +{ + "name": "Finance Administrator", + "description": "Can manage all financial operations" +} diff --git a/tests/Fixtures/update_role.json b/tests/Fixtures/update_role.json new file mode 100644 index 00000000..339fb5b5 --- /dev/null +++ b/tests/Fixtures/update_role.json @@ -0,0 +1,4 @@ +{ + "name": "Super Administrator", + "description": "Full administrative access to all resources" +} diff --git a/tests/Fixtures/update_user.json b/tests/Fixtures/update_user.json new file mode 100644 index 00000000..7242be17 --- /dev/null +++ b/tests/Fixtures/update_user.json @@ -0,0 +1,14 @@ +{ + "email": "marcelina.davis@example.com", + "first_name": "Marcelina", + "last_name": "Davis", + "email_verified": true, + "password": "strong_password_123!", + "password_hash": "$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy", + "password_hash_type": "bcrypt", + "metadata": { + "timezone": "America/New_York" + }, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "locale": "en-US" +} diff --git a/tests/Fixtures/update_user_organization_membership.json b/tests/Fixtures/update_user_organization_membership.json new file mode 100644 index 00000000..d76ea5c3 --- /dev/null +++ b/tests/Fixtures/update_user_organization_membership.json @@ -0,0 +1,6 @@ +{ + "role_slug": "admin", + "role_slugs": [ + "admin" + ] +} diff --git a/tests/Fixtures/update_webhook_endpoint.json b/tests/Fixtures/update_webhook_endpoint.json new file mode 100644 index 00000000..7bfe7e33 --- /dev/null +++ b/tests/Fixtures/update_webhook_endpoint.json @@ -0,0 +1,8 @@ +{ + "endpoint_url": "https://example.com/webhooks", + "status": "enabled", + "events": [ + "user.created", + "dsync.user.created" + ] +} diff --git a/tests/Fixtures/user.json b/tests/Fixtures/user.json new file mode 100644 index 00000000..ea8be141 --- /dev/null +++ b/tests/Fixtures/user.json @@ -0,0 +1,17 @@ +{ + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": true, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": { + "timezone": "America/New_York" + }, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/user_authentication_factor_enroll_response.json b/tests/Fixtures/user_authentication_factor_enroll_response.json new file mode 100644 index 00000000..49b9187a --- /dev/null +++ b/tests/Fixtures/user_authentication_factor_enroll_response.json @@ -0,0 +1,29 @@ +{ + "authentication_factor": { + "object": "authentication_factor", + "id": "auth_factor_01FVYZ5QM8N98T9ME5BCB2BBMJ", + "type": "totp", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "sms": { + "phone_number": "+15005550006" + }, + "totp": { + "issuer": "WorkOS", + "user": "user@example.com", + "secret": "JBSWY3DPEHPK3PXP", + "qr_code": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...", + "uri": "otpauth://totp/WorkOS:user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=WorkOS" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "authentication_challenge": { + "object": "authentication_challenge", + "id": "auth_challenge_01FVYZ5QM8N98T9ME5BCB2BBMJ", + "expires_at": "2026-01-15T12:00:00.000Z", + "code": "123456", + "authentication_factor_id": "auth_factor_01FVYZ5QM8N98T9ME5BCB2BBMJ", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } +} diff --git a/tests/Fixtures/user_authentication_factor_list_list_metadata.json b/tests/Fixtures/user_authentication_factor_list_list_metadata.json new file mode 100644 index 00000000..52f88588 --- /dev/null +++ b/tests/Fixtures/user_authentication_factor_list_list_metadata.json @@ -0,0 +1,4 @@ +{ + "before": "auth_factor_01HXYZ123456789ABCDEFGHIJ", + "after": "auth_factor_01HXYZ987654321KJIHGFEDCBA" +} diff --git a/tests/Fixtures/user_consent_option.json b/tests/Fixtures/user_consent_option.json new file mode 100644 index 00000000..ba21c619 --- /dev/null +++ b/tests/Fixtures/user_consent_option.json @@ -0,0 +1,11 @@ +{ + "claim": "tos_accepted", + "type": "enum", + "label": "Terms of Service", + "choices": [ + { + "value": "accepted", + "label": "I accept the Terms of Service" + } + ] +} diff --git a/tests/Fixtures/user_consent_option_choice.json b/tests/Fixtures/user_consent_option_choice.json new file mode 100644 index 00000000..c5f1f838 --- /dev/null +++ b/tests/Fixtures/user_consent_option_choice.json @@ -0,0 +1,4 @@ +{ + "value": "accepted", + "label": "I accept the Terms of Service" +} diff --git a/tests/Fixtures/user_created.json b/tests/Fixtures/user_created.json new file mode 100644 index 00000000..b1082b0a --- /dev/null +++ b/tests/Fixtures/user_created.json @@ -0,0 +1,43 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "user.created", + "data": { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": true, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": { + "timezone": "America/New_York" + }, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/user_created_context.json b/tests/Fixtures/user_created_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/user_created_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/user_created_context_actor.json b/tests/Fixtures/user_created_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/user_created_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/user_created_context_google_analytics_session.json b/tests/Fixtures/user_created_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/user_created_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/user_created_data.json b/tests/Fixtures/user_created_data.json new file mode 100644 index 00000000..ea8be141 --- /dev/null +++ b/tests/Fixtures/user_created_data.json @@ -0,0 +1,17 @@ +{ + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": true, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": { + "timezone": "America/New_York" + }, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/user_deleted.json b/tests/Fixtures/user_deleted.json new file mode 100644 index 00000000..94b795f0 --- /dev/null +++ b/tests/Fixtures/user_deleted.json @@ -0,0 +1,43 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "user.deleted", + "data": { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": true, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": { + "timezone": "America/New_York" + }, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/user_deleted_context.json b/tests/Fixtures/user_deleted_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/user_deleted_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/user_deleted_context_actor.json b/tests/Fixtures/user_deleted_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/user_deleted_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/user_deleted_context_google_analytics_session.json b/tests/Fixtures/user_deleted_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/user_deleted_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/user_deleted_data.json b/tests/Fixtures/user_deleted_data.json new file mode 100644 index 00000000..ea8be141 --- /dev/null +++ b/tests/Fixtures/user_deleted_data.json @@ -0,0 +1,17 @@ +{ + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": true, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": { + "timezone": "America/New_York" + }, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/user_identities_get_item.json b/tests/Fixtures/user_identities_get_item.json new file mode 100644 index 00000000..46a77e2e --- /dev/null +++ b/tests/Fixtures/user_identities_get_item.json @@ -0,0 +1,5 @@ +{ + "idp_id": "4F42ABDE-1E44-4B66-824A-5F733C037A6D", + "type": "OAuth", + "provider": "MicrosoftOAuth" +} diff --git a/tests/Fixtures/user_invite.json b/tests/Fixtures/user_invite.json new file mode 100644 index 00000000..b3a1dbbd --- /dev/null +++ b/tests/Fixtures/user_invite.json @@ -0,0 +1,16 @@ +{ + "object": "invitation", + "id": "invitation_01E4ZCR3C56J083X43JQXF3JK5", + "email": "marcelina.davis@example.com", + "state": "pending", + "accepted_at": null, + "revoked_at": null, + "expires_at": "2026-01-15T12:00:00.000Z", + "organization_id": "org_01E4ZCR3C56J083X43JQXF3JK5", + "inviter_user_id": "user_01HYGBX8ZGD19949T3BM4FW1C3", + "accepted_user_id": null, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "token": "Z1uX3RbwcIl5fIGJJJCXXisdI", + "accept_invitation_url": "https://your-app.com/invite?invitation_token=Z1uX3RbwcIl5fIGJJJCXXisdI" +} diff --git a/tests/Fixtures/user_list_list_metadata.json b/tests/Fixtures/user_list_list_metadata.json new file mode 100644 index 00000000..9c01753b --- /dev/null +++ b/tests/Fixtures/user_list_list_metadata.json @@ -0,0 +1,4 @@ +{ + "before": "user_01HXYZ123456789ABCDEFGHIJ", + "after": "user_01HXYZ987654321KJIHGFEDCBA" +} diff --git a/tests/Fixtures/user_management_login_request.json b/tests/Fixtures/user_management_login_request.json new file mode 100644 index 00000000..952fbbf4 --- /dev/null +++ b/tests/Fixtures/user_management_login_request.json @@ -0,0 +1,26 @@ +{ + "external_auth_id": "ext_auth_01HXYZ123456789ABCDEFGHIJ", + "user": { + "id": "user_12345", + "email": "marcelina.davis@example.com", + "first_name": "Marcelina", + "last_name": "Davis", + "metadata": { + "department": "Engineering", + "role": "Developer" + } + }, + "user_consent_options": [ + { + "claim": "tos_accepted", + "type": "enum", + "label": "Terms of Service", + "choices": [ + { + "value": "accepted", + "label": "I accept the Terms of Service" + } + ] + } + ] +} diff --git a/tests/Fixtures/user_object.json b/tests/Fixtures/user_object.json new file mode 100644 index 00000000..27b814fd --- /dev/null +++ b/tests/Fixtures/user_object.json @@ -0,0 +1,10 @@ +{ + "id": "user_12345", + "email": "marcelina.davis@example.com", + "first_name": "Marcelina", + "last_name": "Davis", + "metadata": { + "department": "Engineering", + "role": "Developer" + } +} diff --git a/tests/Fixtures/user_organization_membership.json b/tests/Fixtures/user_organization_membership.json new file mode 100644 index 00000000..d6acfbe6 --- /dev/null +++ b/tests/Fixtures/user_organization_membership.json @@ -0,0 +1,19 @@ +{ + "object": "organization_membership", + "id": "om_01HXYZ123456789ABCDEFGHIJ", + "user_id": "user_01EHQTV6MWP9P1F4ZXGXMC8ABB", + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", + "status": "active", + "directory_managed": false, + "organization_name": "Acme Corp", + "custom_attributes": { + "department": "Engineering", + "title": "Developer Experience Engineer", + "location": "Brooklyn" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z", + "role": { + "slug": "admin" + } +} diff --git a/tests/Fixtures/user_organization_membership_base_list_data.json b/tests/Fixtures/user_organization_membership_base_list_data.json new file mode 100644 index 00000000..a4e9ebde --- /dev/null +++ b/tests/Fixtures/user_organization_membership_base_list_data.json @@ -0,0 +1,16 @@ +{ + "object": "organization_membership", + "id": "om_01HXYZ123456789ABCDEFGHIJ", + "user_id": "user_01EHQTV6MWP9P1F4ZXGXMC8ABB", + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", + "status": "active", + "directory_managed": false, + "organization_name": "Acme Corp", + "custom_attributes": { + "department": "Engineering", + "title": "Developer Experience Engineer", + "location": "Brooklyn" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/user_organization_membership_base_list_list_metadata.json b/tests/Fixtures/user_organization_membership_base_list_list_metadata.json new file mode 100644 index 00000000..7c2defd9 --- /dev/null +++ b/tests/Fixtures/user_organization_membership_base_list_list_metadata.json @@ -0,0 +1,4 @@ +{ + "before": "om_01HXYZ123456789ABCDEFGHIJ", + "after": "om_01HXYZ987654321KJIHGFEDCBA" +} diff --git a/tests/Fixtures/user_sessions_impersonator.json b/tests/Fixtures/user_sessions_impersonator.json new file mode 100644 index 00000000..b483e3f0 --- /dev/null +++ b/tests/Fixtures/user_sessions_impersonator.json @@ -0,0 +1,4 @@ +{ + "email": "admin@foocorp.com", + "reason": "Investigating an issue with the customer's account." +} diff --git a/tests/Fixtures/user_sessions_list_item.json b/tests/Fixtures/user_sessions_list_item.json new file mode 100644 index 00000000..233ec56a --- /dev/null +++ b/tests/Fixtures/user_sessions_list_item.json @@ -0,0 +1,18 @@ +{ + "object": "session", + "id": "session_01H93ZY4F80QPBEZ1R5B2SHQG8", + "impersonator": { + "email": "admin@foocorp.com", + "reason": "Investigating an issue with the customer's account." + }, + "ip_address": "198.51.100.42", + "organization_id": "org_01H945H0YD4F97JN9MATX7BYAG", + "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "auth_method": "sso", + "status": "active", + "expires_at": "2026-01-15T12:00:00.000Z", + "ended_at": null, + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/user_updated.json b/tests/Fixtures/user_updated.json new file mode 100644 index 00000000..1694e77d --- /dev/null +++ b/tests/Fixtures/user_updated.json @@ -0,0 +1,43 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "user.updated", + "data": { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": true, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": { + "timezone": "America/New_York" + }, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/user_updated_context.json b/tests/Fixtures/user_updated_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/user_updated_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/user_updated_context_actor.json b/tests/Fixtures/user_updated_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/user_updated_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/user_updated_context_google_analytics_session.json b/tests/Fixtures/user_updated_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/user_updated_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/user_updated_data.json b/tests/Fixtures/user_updated_data.json new file mode 100644 index 00000000..ea8be141 --- /dev/null +++ b/tests/Fixtures/user_updated_data.json @@ -0,0 +1,17 @@ +{ + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": true, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": { + "timezone": "America/New_York" + }, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/validate_api_key.json b/tests/Fixtures/validate_api_key.json new file mode 100644 index 00000000..d859ae78 --- /dev/null +++ b/tests/Fixtures/validate_api_key.json @@ -0,0 +1,3 @@ +{ + "value": "sk_example_1234567890abcdef" +} diff --git a/tests/Fixtures/vault_byok_key_verification_completed.json b/tests/Fixtures/vault_byok_key_verification_completed.json new file mode 100644 index 00000000..06e645c8 --- /dev/null +++ b/tests/Fixtures/vault_byok_key_verification_completed.json @@ -0,0 +1,31 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "vault.byok_key.verification_completed", + "data": { + "organization_id": "org_01EHT88Z8J8795GZNQ4ZP1J81T", + "key_provider": "AWS_KMS", + "verified": true + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/vault_byok_key_verification_completed_context.json b/tests/Fixtures/vault_byok_key_verification_completed_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/vault_byok_key_verification_completed_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/vault_byok_key_verification_completed_context_actor.json b/tests/Fixtures/vault_byok_key_verification_completed_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/vault_byok_key_verification_completed_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/vault_byok_key_verification_completed_context_google_analytics_session.json b/tests/Fixtures/vault_byok_key_verification_completed_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/vault_byok_key_verification_completed_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/vault_byok_key_verification_completed_data.json b/tests/Fixtures/vault_byok_key_verification_completed_data.json new file mode 100644 index 00000000..38d261be --- /dev/null +++ b/tests/Fixtures/vault_byok_key_verification_completed_data.json @@ -0,0 +1,5 @@ +{ + "organization_id": "org_01EHT88Z8J8795GZNQ4ZP1J81T", + "key_provider": "AWS_KMS", + "verified": true +} diff --git a/tests/Fixtures/vault_data_created.json b/tests/Fixtures/vault_data_created.json new file mode 100644 index 00000000..d84b80fa --- /dev/null +++ b/tests/Fixtures/vault_data_created.json @@ -0,0 +1,36 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "vault.data.created", + "data": { + "actor_id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor_source": "api", + "actor_name": "Jane Doe", + "kv_name": "user-secrets", + "key_id": "key_01EHWNCE74X7JSDV0X3SZ3KJNY", + "key_context": { + "key": "test_value" + } + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/vault_data_created_context.json b/tests/Fixtures/vault_data_created_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/vault_data_created_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/vault_data_created_context_actor.json b/tests/Fixtures/vault_data_created_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/vault_data_created_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/vault_data_created_context_google_analytics_session.json b/tests/Fixtures/vault_data_created_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/vault_data_created_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/vault_data_created_data.json b/tests/Fixtures/vault_data_created_data.json new file mode 100644 index 00000000..5e20a2f6 --- /dev/null +++ b/tests/Fixtures/vault_data_created_data.json @@ -0,0 +1,10 @@ +{ + "actor_id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor_source": "api", + "actor_name": "Jane Doe", + "kv_name": "user-secrets", + "key_id": "key_01EHWNCE74X7JSDV0X3SZ3KJNY", + "key_context": { + "key": "test_value" + } +} diff --git a/tests/Fixtures/vault_data_deleted.json b/tests/Fixtures/vault_data_deleted.json new file mode 100644 index 00000000..bedbef03 --- /dev/null +++ b/tests/Fixtures/vault_data_deleted.json @@ -0,0 +1,32 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "vault.data.deleted", + "data": { + "actor_id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor_source": "api", + "actor_name": "Jane Doe", + "kv_name": "user-secrets" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/vault_data_deleted_context.json b/tests/Fixtures/vault_data_deleted_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/vault_data_deleted_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/vault_data_deleted_context_actor.json b/tests/Fixtures/vault_data_deleted_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/vault_data_deleted_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/vault_data_deleted_context_google_analytics_session.json b/tests/Fixtures/vault_data_deleted_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/vault_data_deleted_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/vault_data_deleted_data.json b/tests/Fixtures/vault_data_deleted_data.json new file mode 100644 index 00000000..4ee08515 --- /dev/null +++ b/tests/Fixtures/vault_data_deleted_data.json @@ -0,0 +1,6 @@ +{ + "actor_id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor_source": "api", + "actor_name": "Jane Doe", + "kv_name": "user-secrets" +} diff --git a/tests/Fixtures/vault_data_read.json b/tests/Fixtures/vault_data_read.json new file mode 100644 index 00000000..27ba4181 --- /dev/null +++ b/tests/Fixtures/vault_data_read.json @@ -0,0 +1,33 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "vault.data.read", + "data": { + "actor_id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor_source": "api", + "actor_name": "Jane Doe", + "kv_name": "user-secrets", + "key_id": "key_01EHWNCE74X7JSDV0X3SZ3KJNY" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/vault_data_read_context.json b/tests/Fixtures/vault_data_read_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/vault_data_read_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/vault_data_read_context_actor.json b/tests/Fixtures/vault_data_read_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/vault_data_read_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/vault_data_read_context_google_analytics_session.json b/tests/Fixtures/vault_data_read_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/vault_data_read_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/vault_data_read_data.json b/tests/Fixtures/vault_data_read_data.json new file mode 100644 index 00000000..23bb14c2 --- /dev/null +++ b/tests/Fixtures/vault_data_read_data.json @@ -0,0 +1,7 @@ +{ + "actor_id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor_source": "api", + "actor_name": "Jane Doe", + "kv_name": "user-secrets", + "key_id": "key_01EHWNCE74X7JSDV0X3SZ3KJNY" +} diff --git a/tests/Fixtures/vault_data_updated.json b/tests/Fixtures/vault_data_updated.json new file mode 100644 index 00000000..2edb07da --- /dev/null +++ b/tests/Fixtures/vault_data_updated.json @@ -0,0 +1,36 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "vault.data.updated", + "data": { + "actor_id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor_source": "api", + "actor_name": "Jane Doe", + "kv_name": "user-secrets", + "key_id": "key_01EHWNCE74X7JSDV0X3SZ3KJNY", + "key_context": { + "key": "test_value" + } + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/vault_data_updated_context.json b/tests/Fixtures/vault_data_updated_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/vault_data_updated_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/vault_data_updated_context_actor.json b/tests/Fixtures/vault_data_updated_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/vault_data_updated_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/vault_data_updated_context_google_analytics_session.json b/tests/Fixtures/vault_data_updated_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/vault_data_updated_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/vault_data_updated_data.json b/tests/Fixtures/vault_data_updated_data.json new file mode 100644 index 00000000..5e20a2f6 --- /dev/null +++ b/tests/Fixtures/vault_data_updated_data.json @@ -0,0 +1,10 @@ +{ + "actor_id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor_source": "api", + "actor_name": "Jane Doe", + "kv_name": "user-secrets", + "key_id": "key_01EHWNCE74X7JSDV0X3SZ3KJNY", + "key_context": { + "key": "test_value" + } +} diff --git a/tests/Fixtures/vault_dek_decrypted.json b/tests/Fixtures/vault_dek_decrypted.json new file mode 100644 index 00000000..632186c5 --- /dev/null +++ b/tests/Fixtures/vault_dek_decrypted.json @@ -0,0 +1,32 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "vault.dek.decrypted", + "data": { + "actor_id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor_source": "api", + "actor_name": "Jane Doe", + "key_id": "key_01EHWNCE74X7JSDV0X3SZ3KJNY" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/vault_dek_decrypted_context.json b/tests/Fixtures/vault_dek_decrypted_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/vault_dek_decrypted_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/vault_dek_decrypted_context_actor.json b/tests/Fixtures/vault_dek_decrypted_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/vault_dek_decrypted_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/vault_dek_decrypted_context_google_analytics_session.json b/tests/Fixtures/vault_dek_decrypted_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/vault_dek_decrypted_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/vault_dek_decrypted_data.json b/tests/Fixtures/vault_dek_decrypted_data.json new file mode 100644 index 00000000..ef970f6a --- /dev/null +++ b/tests/Fixtures/vault_dek_decrypted_data.json @@ -0,0 +1,6 @@ +{ + "actor_id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor_source": "api", + "actor_name": "Jane Doe", + "key_id": "key_01EHWNCE74X7JSDV0X3SZ3KJNY" +} diff --git a/tests/Fixtures/vault_dek_read.json b/tests/Fixtures/vault_dek_read.json new file mode 100644 index 00000000..3c12bc57 --- /dev/null +++ b/tests/Fixtures/vault_dek_read.json @@ -0,0 +1,37 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "vault.dek.read", + "data": { + "actor_id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor_source": "api", + "actor_name": "Jane Doe", + "key_ids": [ + "dek_01EHWNCE74X7JSDV0X3SZ3KJNY" + ], + "key_context": { + "key": "test_value" + } + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/vault_dek_read_context.json b/tests/Fixtures/vault_dek_read_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/vault_dek_read_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/vault_dek_read_context_actor.json b/tests/Fixtures/vault_dek_read_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/vault_dek_read_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/vault_dek_read_context_google_analytics_session.json b/tests/Fixtures/vault_dek_read_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/vault_dek_read_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/vault_dek_read_data.json b/tests/Fixtures/vault_dek_read_data.json new file mode 100644 index 00000000..1fcf4c74 --- /dev/null +++ b/tests/Fixtures/vault_dek_read_data.json @@ -0,0 +1,11 @@ +{ + "actor_id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor_source": "api", + "actor_name": "Jane Doe", + "key_ids": [ + "dek_01EHWNCE74X7JSDV0X3SZ3KJNY" + ], + "key_context": { + "key": "test_value" + } +} diff --git a/tests/Fixtures/vault_kek_created.json b/tests/Fixtures/vault_kek_created.json new file mode 100644 index 00000000..9321861b --- /dev/null +++ b/tests/Fixtures/vault_kek_created.json @@ -0,0 +1,33 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "vault.kek.created", + "data": { + "actor_id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor_source": "api", + "actor_name": "Jane Doe", + "key_name": "production-kek", + "key_id": "key_01EHWNCE74X7JSDV0X3SZ3KJNY" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/vault_kek_created_context.json b/tests/Fixtures/vault_kek_created_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/vault_kek_created_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/vault_kek_created_context_actor.json b/tests/Fixtures/vault_kek_created_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/vault_kek_created_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/vault_kek_created_context_google_analytics_session.json b/tests/Fixtures/vault_kek_created_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/vault_kek_created_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/vault_kek_created_data.json b/tests/Fixtures/vault_kek_created_data.json new file mode 100644 index 00000000..91d90957 --- /dev/null +++ b/tests/Fixtures/vault_kek_created_data.json @@ -0,0 +1,7 @@ +{ + "actor_id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor_source": "api", + "actor_name": "Jane Doe", + "key_name": "production-kek", + "key_id": "key_01EHWNCE74X7JSDV0X3SZ3KJNY" +} diff --git a/tests/Fixtures/vault_metadata_read.json b/tests/Fixtures/vault_metadata_read.json new file mode 100644 index 00000000..102b4ef6 --- /dev/null +++ b/tests/Fixtures/vault_metadata_read.json @@ -0,0 +1,32 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "vault.metadata.read", + "data": { + "actor_id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor_source": "api", + "actor_name": "Jane Doe", + "kv_name": "user-secrets" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/vault_metadata_read_context.json b/tests/Fixtures/vault_metadata_read_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/vault_metadata_read_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/vault_metadata_read_context_actor.json b/tests/Fixtures/vault_metadata_read_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/vault_metadata_read_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/vault_metadata_read_context_google_analytics_session.json b/tests/Fixtures/vault_metadata_read_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/vault_metadata_read_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/vault_metadata_read_data.json b/tests/Fixtures/vault_metadata_read_data.json new file mode 100644 index 00000000..4ee08515 --- /dev/null +++ b/tests/Fixtures/vault_metadata_read_data.json @@ -0,0 +1,6 @@ +{ + "actor_id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor_source": "api", + "actor_name": "Jane Doe", + "kv_name": "user-secrets" +} diff --git a/tests/Fixtures/vault_names_listed.json b/tests/Fixtures/vault_names_listed.json new file mode 100644 index 00000000..b91d9539 --- /dev/null +++ b/tests/Fixtures/vault_names_listed.json @@ -0,0 +1,31 @@ +{ + "id": "event_01EHZNVPK3SFK441A1RGBFSHRT", + "event": "vault.names.listed", + "data": { + "actor_id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor_source": "api", + "actor_name": "Jane Doe" + }, + "created_at": "2026-01-15T12:00:00.000Z", + "context": { + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } + }, + "object": "event" +} diff --git a/tests/Fixtures/vault_names_listed_context.json b/tests/Fixtures/vault_names_listed_context.json new file mode 100644 index 00000000..7ad61935 --- /dev/null +++ b/tests/Fixtures/vault_names_listed_context.json @@ -0,0 +1,20 @@ +{ + "google_analytics_client_id": "GA1.2.1234567890.1234567890", + "google_analytics_sessions": [ + { + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" + } + ], + "ajs_anonymous_id": "ajs_anon_01EHWNCE74X7JSDV0X3SZ3KJNY", + "client_id": "client_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor": { + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" + }, + "previous_attributes": { + "key": {} + } +} diff --git a/tests/Fixtures/vault_names_listed_context_actor.json b/tests/Fixtures/vault_names_listed_context_actor.json new file mode 100644 index 00000000..bb79a150 --- /dev/null +++ b/tests/Fixtures/vault_names_listed_context_actor.json @@ -0,0 +1,5 @@ +{ + "id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "source": "api", + "name": "Jane Doe" +} diff --git a/tests/Fixtures/vault_names_listed_context_google_analytics_session.json b/tests/Fixtures/vault_names_listed_context_google_analytics_session.json new file mode 100644 index 00000000..a16fcbbd --- /dev/null +++ b/tests/Fixtures/vault_names_listed_context_google_analytics_session.json @@ -0,0 +1,5 @@ +{ + "containerId": "GTM-ABCDEF", + "sessionId": "1234567890", + "sessionNumber": "1" +} diff --git a/tests/Fixtures/vault_names_listed_data.json b/tests/Fixtures/vault_names_listed_data.json new file mode 100644 index 00000000..3fef4234 --- /dev/null +++ b/tests/Fixtures/vault_names_listed_data.json @@ -0,0 +1,5 @@ +{ + "actor_id": "user_01EHWNCE74X7JSDV0X3SZ3KJNY", + "actor_source": "api", + "actor_name": "Jane Doe" +} diff --git a/tests/Fixtures/verify_email_address.json b/tests/Fixtures/verify_email_address.json new file mode 100644 index 00000000..736bf40a --- /dev/null +++ b/tests/Fixtures/verify_email_address.json @@ -0,0 +1,3 @@ +{ + "code": "123456" +} diff --git a/tests/Fixtures/verify_email_response.json b/tests/Fixtures/verify_email_response.json new file mode 100644 index 00000000..647d4c25 --- /dev/null +++ b/tests/Fixtures/verify_email_response.json @@ -0,0 +1,19 @@ +{ + "user": { + "object": "user", + "id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "first_name": "Marcelina", + "last_name": "Davis", + "profile_picture_url": "https://workoscdn.com/images/v1/123abc", + "email": "marcelina.davis@example.com", + "email_verified": true, + "external_id": "f1ffa2b2-c20b-4d39-be5c-212726e11222", + "metadata": { + "timezone": "America/New_York" + }, + "last_sign_in_at": "2025-06-25T19:07:33.155Z", + "locale": "en-US", + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" + } +} diff --git a/tests/Fixtures/webhook_endpoint_json.json b/tests/Fixtures/webhook_endpoint_json.json new file mode 100644 index 00000000..3f37fa02 --- /dev/null +++ b/tests/Fixtures/webhook_endpoint_json.json @@ -0,0 +1,13 @@ +{ + "object": "webhook_endpoint", + "id": "we_0123456789", + "endpoint_url": "https://example.com/webhooks", + "secret": "whsec_0FWAiVGkEfGBqqsJH4aNAGBJ4", + "status": "enabled", + "events": [ + "user.created", + "dsync.user.created" + ], + "created_at": "2026-01-15T12:00:00.000Z", + "updated_at": "2026-01-15T12:00:00.000Z" +} diff --git a/tests/Fixtures/webhook_endpoint_list_list_metadata.json b/tests/Fixtures/webhook_endpoint_list_list_metadata.json new file mode 100644 index 00000000..70881ab6 --- /dev/null +++ b/tests/Fixtures/webhook_endpoint_list_list_metadata.json @@ -0,0 +1,4 @@ +{ + "before": "we_01HXYZ123456789ABCDEFGHIJ", + "after": "we_01HXYZ987654321KJIHGFEDCBA" +} diff --git a/tests/Fixtures/widget_session_token.json b/tests/Fixtures/widget_session_token.json new file mode 100644 index 00000000..0f0c903a --- /dev/null +++ b/tests/Fixtures/widget_session_token.json @@ -0,0 +1,7 @@ +{ + "organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT", + "user_id": "user_01E4ZCR3C56J083X43JQXF3JK5", + "scopes": [ + "widgets:users-table:manage" + ] +} diff --git a/tests/Fixtures/widget_session_token_response.json b/tests/Fixtures/widget_session_token_response.json new file mode 100644 index 00000000..0a78c2fd --- /dev/null +++ b/tests/Fixtures/widget_session_token_response.json @@ -0,0 +1,3 @@ +{ + "token": "eyJhbGciOiJSUzI1NiIsImtpZCI6InNlc3Npb24..." +} diff --git a/tests/PKCEHelperTest.php b/tests/PKCEHelperTest.php new file mode 100644 index 00000000..df2e19de --- /dev/null +++ b/tests/PKCEHelperTest.php @@ -0,0 +1,161 @@ +assertSame(43, strlen($verifier)); + // base64url: only [A-Za-z0-9_-] + $this->assertMatchesRegularExpression('/^[A-Za-z0-9_-]+$/', $verifier); + } + + public function testGenerateCodeVerifierCustomLength(): void + { + $verifier = PKCEHelper::generateCodeVerifier(128); + $this->assertSame(128, strlen($verifier)); + } + + public function testGenerateCodeVerifierTooShort(): void + { + $this->expectException(\InvalidArgumentException::class); + PKCEHelper::generateCodeVerifier(42); + } + + public function testGenerateCodeVerifierTooLong(): void + { + $this->expectException(\InvalidArgumentException::class); + PKCEHelper::generateCodeVerifier(129); + } + + public function testGenerateCodeChallenge(): void + { + $verifier = 'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk'; + $challenge = PKCEHelper::generateCodeChallenge($verifier); + // S256: base64url(SHA256(verifier)) + $expected = rtrim(strtr(base64_encode(hash('sha256', $verifier, true)), '+/', '-_'), '='); + $this->assertSame($expected, $challenge); + } + + public function testGenerate(): void + { + $pair = PKCEHelper::generate(); + $this->assertArrayHasKey('code_verifier', $pair); + $this->assertArrayHasKey('code_challenge', $pair); + $this->assertSame('S256', $pair['code_challenge_method']); + + // Verify the challenge matches the verifier + $expectedChallenge = PKCEHelper::generateCodeChallenge($pair['code_verifier']); + $this->assertSame($expectedChallenge, $pair['code_challenge']); + } + + // -- H10: AuthKit PKCE authorization URL -- + + public function testGetAuthKitAuthorizationUrl(): void + { + $client = $this->createMockClient([['status' => 200, 'body' => ['url' => 'https://auth.workos.com/...']]]); + $result = $client->pkce()->getAuthKitAuthorizationUrl( + redirectUri: 'https://example.com/callback', + clientId: 'client_123', + ); + $this->assertArrayHasKey('code_verifier', $result); + $this->assertArrayHasKey('state', $result); + $this->assertSame(43, strlen($result['code_verifier'])); + $this->assertSame(32, strlen($result['state'])); // hex-encoded 16 bytes + + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $query = []; + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('code', $query['response_type']); + $this->assertSame('S256', $query['code_challenge_method']); + } + + // -- H11: AuthKit PKCE code exchange -- + + public function testAuthKitCodeExchange(): void + { + $fixture = ['access_token' => 'at_123', 'user' => ['id' => 'usr_1']]; + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->pkce()->authKitCodeExchange( + code: 'auth_code_123', + codeVerifier: 'verifier_123', + clientId: 'client_123', + ); + $this->assertSame('at_123', $result['access_token']); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('authorization_code', $body['grant_type']); + $this->assertSame('verifier_123', $body['code_verifier']); + } + + // -- H15: SSO PKCE authorization URL -- + + public function testGetSsoAuthorizationUrl(): void + { + $client = $this->createMockClient([['status' => 200, 'body' => ['url' => 'https://auth.workos.com/sso/...']]]); + $result = $client->pkce()->getSsoAuthorizationUrl( + redirectUri: 'https://example.com/callback', + clientId: 'client_123', + domain: 'example.com', + ); + $this->assertArrayHasKey('code_verifier', $result); + $this->assertArrayHasKey('state', $result); + + $request = $this->getLastRequest(); + $query = []; + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('code', $query['response_type']); + $this->assertSame('S256', $query['code_challenge_method']); + $this->assertSame('example.com', $query['domain']); + } + + // -- H16: SSO PKCE code exchange -- + + public function testSsoCodeExchange(): void + { + $fixture = ['access_token' => 'at_sso', 'profile' => ['id' => 'prof_1']]; + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->pkce()->ssoCodeExchange( + code: 'sso_code_123', + codeVerifier: 'verifier_sso', + clientId: 'client_123', + ); + $this->assertSame('at_sso', $result['access_token']); + $request = $this->getLastRequest(); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('verifier_sso', $body['code_verifier']); + } + + // -- H19: Public client factory -- + + public function testCreatePublicClient(): void + { + $client = PKCEHelper::createPublicClient('client_123'); + $this->assertInstanceOf(WorkOS::class, $client); + $httpClientProperty = new \ReflectionProperty($client, 'httpClient'); + $this->assertSame('client_123', $httpClientProperty->getValue($client)->getClientId()); + } + + public function testPkceAccessibleFromClient(): void + { + $client = $this->createMockClient([]); + $this->assertInstanceOf(PKCEHelper::class, $client->pkce()); + } +} diff --git a/tests/PasswordlessTest.php b/tests/PasswordlessTest.php new file mode 100644 index 00000000..b468efc9 --- /dev/null +++ b/tests/PasswordlessTest.php @@ -0,0 +1,54 @@ + 'passwordless_session', + 'id' => 'passwordless_session_01EZCZ', + 'email' => 'user@example.com', + 'expires_at' => '2024-01-01T00:00:00Z', + 'link' => 'https://auth.workos.com/passwordless/01EZCZ/confirm', + ]; + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->passwordless()->createSession(email: 'user@example.com'); + $this->assertIsArray($result); + $this->assertSame('passwordless_session', $result['object']); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('passwordless/sessions', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('user@example.com', $body['email']); + $this->assertSame('MagicLink', $body['type']); + } + + public function testSendSession(): void + { + $client = $this->createMockClient([['status' => 204]]); + $client->passwordless()->sendSession('passwordless_session_01EZCZ'); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith( + 'passwordless/sessions/passwordless_session_01EZCZ/send', + $request->getUri()->getPath() + ); + } + + public function testPasswordlessAccessibleFromClient(): void + { + $client = $this->createMockClient([]); + $this->assertInstanceOf(\WorkOS\Passwordless::class, $client->passwordless()); + } +} diff --git a/tests/Service/AdminPortalTest.php b/tests/Service/AdminPortalTest.php new file mode 100644 index 00000000..90d75260 --- /dev/null +++ b/tests/Service/AdminPortalTest.php @@ -0,0 +1,30 @@ +loadFixture('portal_link_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->adminPortal()->generateLink(organization: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\PortalLinkResponse::class, $result); + $this->assertSame($fixture['link'], $result->link); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('portal/generate_link', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['organization']); + } +} diff --git a/tests/Service/ApiKeysTest.php b/tests/Service/ApiKeysTest.php new file mode 100644 index 00000000..77487c73 --- /dev/null +++ b/tests/Service/ApiKeysTest.php @@ -0,0 +1,89 @@ +loadFixture('api_key_validation_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->apiKeys()->createValidations(value: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\ApiKeyValidationResponse::class, $result); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('api_keys/validations', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['value']); + } + + public function testDeleteApiKey(): void + { + $client = $this->createMockClient([['status' => 204]]); + $client->apiKeys()->deleteApiKey('test_id'); + $request = $this->getLastRequest(); + $this->assertSame('DELETE', $request->getMethod()); + $this->assertStringEndsWith('api_keys/test_id', $request->getUri()->getPath()); + } + + public function testListOrganizationApiKeys(): void + { + $fixture = $this->loadFixture('list_api_key'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->apiKeys()->listOrganizationApiKeys('test_organizationId', before: 'test_value', after: 'test_value', limit: 1, order: \WorkOS\Resource\EventsOrder::Normal); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('organizations/test_organizationId/api_keys', $request->getUri()->getPath()); + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('test_value', $query['before']); + $this->assertSame('test_value', $query['after']); + $this->assertArrayHasKey('limit', $query); + $this->assertSame('normal', $query['order']); + } + + public function testCreateOrganizationApiKeys(): void + { + $fixture = $this->loadFixture('api_key_with_value'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->apiKeys()->createOrganizationApiKeys('test_organizationId', name: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\ApiKeyWithValue::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['name'], $result->name); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('organizations/test_organizationId/api_keys', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['name']); + } + + public function testPaginationBoundary(): void + { + $fixture = $this->loadFixture('list_api_key'); + // Ensure cursors are null (first/last page boundary) + $fixture['list_metadata']['before'] = null; + $fixture['list_metadata']['after'] = null; + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->apiKeys()->listOrganizationApiKeys('test_organizationId'); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + // Verify cursors are null on boundary page + $this->assertNull($result->listMetadata['before']); + $this->assertNull($result->listMetadata['after']); + // Iterating should not throw on null cursors + foreach ($result as $item) { + $this->assertNotNull($item); + break; + } + } +} diff --git a/tests/Service/AuditLogsTest.php b/tests/Service/AuditLogsTest.php new file mode 100644 index 00000000..8df6bbb2 --- /dev/null +++ b/tests/Service/AuditLogsTest.php @@ -0,0 +1,148 @@ +loadFixture('audit_logs_retention_json'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->auditLogs()->listOrganizationAuditLogsRetention('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\AuditLogsRetentionJson::class, $result); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('organizations/test_id/audit_logs_retention', $request->getUri()->getPath()); + } + + public function testUpdateOrganizationAuditLogsRetention(): void + { + $fixture = $this->loadFixture('audit_logs_retention_json'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->auditLogs()->updateOrganizationAuditLogsRetention('test_id', retentionPeriodInDays: 1); + $this->assertInstanceOf(\WorkOS\Resource\AuditLogsRetentionJson::class, $result); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('PUT', $request->getMethod()); + $this->assertStringEndsWith('organizations/test_id/audit_logs_retention', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame(1, $body['retention_period_in_days']); + } + + public function testListActions(): void + { + $fixture = $this->loadFixture('list_audit_log_action_json'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->auditLogs()->listActions(before: 'test_value', after: 'test_value', limit: 1, order: \WorkOS\Resource\EventsOrder::Normal); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('audit_logs/actions', $request->getUri()->getPath()); + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('test_value', $query['before']); + $this->assertSame('test_value', $query['after']); + $this->assertArrayHasKey('limit', $query); + $this->assertSame('normal', $query['order']); + } + + public function testListActionSchemas(): void + { + $fixture = $this->loadFixture('list_audit_log_schema_json'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->auditLogs()->listActionSchemas('test_actionName', before: 'test_value', after: 'test_value', limit: 1, order: \WorkOS\Resource\EventsOrder::Normal); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('audit_logs/actions/test_actionName/schemas', $request->getUri()->getPath()); + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('test_value', $query['before']); + $this->assertSame('test_value', $query['after']); + $this->assertArrayHasKey('limit', $query); + $this->assertSame('normal', $query['order']); + } + + public function testCreateSchema(): void + { + $fixture = $this->loadFixture('audit_log_schema_json'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->auditLogs()->createSchema('test_actionName', targets: []); + $this->assertInstanceOf(\WorkOS\Resource\AuditLogSchemaJson::class, $result); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('audit_logs/actions/test_actionName/schemas', $request->getUri()->getPath()); + } + + public function testCreateEvent(): void + { + $fixture = $this->loadFixture('audit_log_event_create_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->auditLogs()->createEvent(organizationId: 'test_value', event: \WorkOS\Resource\AuditLogEvent::fromArray($this->loadFixture('audit_log_event'))); + $this->assertInstanceOf(\WorkOS\Resource\AuditLogEventCreateResponse::class, $result); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('audit_logs/events', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['organization_id']); + } + + public function testCreateExport(): void + { + $fixture = $this->loadFixture('audit_log_export_json'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->auditLogs()->createExport(organizationId: 'test_value', rangeStart: 'test_value', rangeEnd: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\AuditLogExportJson::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('audit_logs/exports', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['organization_id']); + $this->assertSame('test_value', $body['range_start']); + $this->assertSame('test_value', $body['range_end']); + } + + public function testGetExport(): void + { + $fixture = $this->loadFixture('audit_log_export_json'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->auditLogs()->getExport('test_auditLogExportId'); + $this->assertInstanceOf(\WorkOS\Resource\AuditLogExportJson::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('audit_logs/exports/test_auditLogExportId', $request->getUri()->getPath()); + } + + public function testPaginationBoundary(): void + { + $fixture = $this->loadFixture('list_audit_log_action_json'); + // Ensure cursors are null (first/last page boundary) + $fixture['list_metadata']['before'] = null; + $fixture['list_metadata']['after'] = null; + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->auditLogs()->listActions(); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + // Verify cursors are null on boundary page + $this->assertNull($result->listMetadata['before']); + $this->assertNull($result->listMetadata['after']); + // Iterating should not throw on null cursors + foreach ($result as $item) { + $this->assertNotNull($item); + break; + } + } +} diff --git a/tests/Service/AuthorizationTest.php b/tests/Service/AuthorizationTest.php new file mode 100644 index 00000000..84901f79 --- /dev/null +++ b/tests/Service/AuthorizationTest.php @@ -0,0 +1,527 @@ +loadFixture('authorization_check'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->check('test_organization_membership_id', permissionSlug: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\AuthorizationCheck::class, $result); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('authorization/organization_memberships/test_organization_membership_id/check', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['permission_slug']); + } + + public function testListOrganizationMembershipResources(): void + { + $fixture = $this->loadFixture('list_authorization_resource'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->listOrganizationMembershipResources('test_organization_membership_id', before: 'test_value', after: 'test_value', limit: 1, order: \WorkOS\Resource\EventsOrder::Normal, permissionSlug: 'test_value', parentResourceId: 'test_value', parentResourceTypeSlug: 'test_value', parentResourceExternalId: 'test_value'); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('authorization/organization_memberships/test_organization_membership_id/resources', $request->getUri()->getPath()); + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('test_value', $query['before']); + $this->assertSame('test_value', $query['after']); + $this->assertArrayHasKey('limit', $query); + $this->assertSame('normal', $query['order']); + $this->assertSame('test_value', $query['permission_slug']); + $this->assertSame('test_value', $query['parent_resource_id']); + $this->assertSame('test_value', $query['parent_resource_type_slug']); + $this->assertSame('test_value', $query['parent_resource_external_id']); + } + + public function testListOrganizationMembershipRoleAssignments(): void + { + $fixture = $this->loadFixture('list_role_assignment'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->listOrganizationMembershipRoleAssignments('test_organization_membership_id', before: 'test_value', after: 'test_value', limit: 1, order: \WorkOS\Resource\EventsOrder::Normal); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('authorization/organization_memberships/test_organization_membership_id/role_assignments', $request->getUri()->getPath()); + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('test_value', $query['before']); + $this->assertSame('test_value', $query['after']); + $this->assertArrayHasKey('limit', $query); + $this->assertSame('normal', $query['order']); + } + + public function testAssignRole(): void + { + $fixture = $this->loadFixture('role_assignment'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->assignRole('test_organization_membership_id', roleSlug: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\RoleAssignment::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('authorization/organization_memberships/test_organization_membership_id/role_assignments', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['role_slug']); + } + + public function testRemoveRole(): void + { + $client = $this->createMockClient([['status' => 204]]); + $client->authorization()->removeRole('test_organization_membership_id', roleSlug: 'test_value'); + $request = $this->getLastRequest(); + $this->assertSame('DELETE', $request->getMethod()); + $this->assertStringEndsWith('authorization/organization_memberships/test_organization_membership_id/role_assignments', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['role_slug']); + } + + public function testDeleteOrganizationMembershipRoleAssignment(): void + { + $client = $this->createMockClient([['status' => 204]]); + $client->authorization()->deleteOrganizationMembershipRoleAssignment('test_organization_membership_id', 'test_role_assignment_id'); + $request = $this->getLastRequest(); + $this->assertSame('DELETE', $request->getMethod()); + $this->assertStringEndsWith('authorization/organization_memberships/test_organization_membership_id/role_assignments/test_role_assignment_id', $request->getUri()->getPath()); + } + + public function testListOrganizationRoles(): void + { + $fixture = $this->loadFixture('role_list'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->listOrganizationRoles('test_organizationId'); + $this->assertInstanceOf(\WorkOS\Resource\RoleList::class, $result); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('authorization/organizations/test_organizationId/roles', $request->getUri()->getPath()); + } + + public function testCreateOrganizationRole(): void + { + $fixture = $this->loadFixture('role'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->createOrganizationRole('test_organizationId', name: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\Role::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['slug'], $result->slug); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('authorization/organizations/test_organizationId/roles', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['name']); + } + + public function testGetOrganizationRole(): void + { + $fixture = $this->loadFixture('role'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->getOrganizationRole('test_organizationId', 'test_slug'); + $this->assertInstanceOf(\WorkOS\Resource\Role::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['slug'], $result->slug); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('authorization/organizations/test_organizationId/roles/test_slug', $request->getUri()->getPath()); + } + + public function testUpdateOrganizationRole(): void + { + $fixture = $this->loadFixture('role'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->updateOrganizationRole('test_organizationId', 'test_slug'); + $this->assertInstanceOf(\WorkOS\Resource\Role::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['slug'], $result->slug); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('PATCH', $request->getMethod()); + $this->assertStringEndsWith('authorization/organizations/test_organizationId/roles/test_slug', $request->getUri()->getPath()); + } + + public function testDeleteOrganizationRole(): void + { + $client = $this->createMockClient([['status' => 204]]); + $client->authorization()->deleteOrganizationRole('test_organizationId', 'test_slug'); + $request = $this->getLastRequest(); + $this->assertSame('DELETE', $request->getMethod()); + $this->assertStringEndsWith('authorization/organizations/test_organizationId/roles/test_slug', $request->getUri()->getPath()); + } + + public function testCreateRolePermissions(): void + { + $fixture = $this->loadFixture('role'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->createRolePermissions('test_organizationId', 'test_slug', bodySlug: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\Role::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['slug'], $result->slug); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('authorization/organizations/test_organizationId/roles/test_slug/permissions', $request->getUri()->getPath()); + } + + public function testUpdateRolePermissions(): void + { + $fixture = $this->loadFixture('role'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->updateRolePermissions('test_organizationId', 'test_slug', permissions: []); + $this->assertInstanceOf(\WorkOS\Resource\Role::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['slug'], $result->slug); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('PUT', $request->getMethod()); + $this->assertStringEndsWith('authorization/organizations/test_organizationId/roles/test_slug/permissions', $request->getUri()->getPath()); + } + + public function testDeleteRolePermission(): void + { + $client = $this->createMockClient([['status' => 204]]); + $client->authorization()->deleteRolePermission('test_organizationId', 'test_slug', 'test_permissionSlug'); + $request = $this->getLastRequest(); + $this->assertSame('DELETE', $request->getMethod()); + $this->assertStringEndsWith('authorization/organizations/test_organizationId/roles/test_slug/permissions/test_permissionSlug', $request->getUri()->getPath()); + } + + public function testGetOrganizationResource(): void + { + $fixture = $this->loadFixture('authorization_resource'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->getOrganizationResource('test_organization_id', 'test_resource_type_slug', 'test_external_id'); + $this->assertInstanceOf(\WorkOS\Resource\AuthorizationResource::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['name'], $result->name); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('authorization/organizations/test_organization_id/resources/test_resource_type_slug/test_external_id', $request->getUri()->getPath()); + } + + public function testUpdateOrganizationResource(): void + { + $fixture = $this->loadFixture('authorization_resource'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->updateOrganizationResource('test_organization_id', 'test_resource_type_slug', 'test_external_id'); + $this->assertInstanceOf(\WorkOS\Resource\AuthorizationResource::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['name'], $result->name); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('PATCH', $request->getMethod()); + $this->assertStringEndsWith('authorization/organizations/test_organization_id/resources/test_resource_type_slug/test_external_id', $request->getUri()->getPath()); + } + + public function testDeleteOrganizationResource(): void + { + $client = $this->createMockClient([['status' => 204]]); + $client->authorization()->deleteOrganizationResource('test_organization_id', 'test_resource_type_slug', 'test_external_id'); + $request = $this->getLastRequest(); + $this->assertSame('DELETE', $request->getMethod()); + $this->assertStringEndsWith('authorization/organizations/test_organization_id/resources/test_resource_type_slug/test_external_id', $request->getUri()->getPath()); + } + + public function testListResourceOrganizationMemberships(): void + { + $fixture = $this->loadFixture('list_user_organization_membership_base_list_data'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->listResourceOrganizationMemberships('test_organization_id', 'test_resource_type_slug', 'test_external_id', before: 'test_value', after: 'test_value', limit: 1, order: \WorkOS\Resource\EventsOrder::Normal, permissionSlug: 'test_value', assignment: \WorkOS\Resource\AuthorizationAssignment::Direct); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('authorization/organizations/test_organization_id/resources/test_resource_type_slug/test_external_id/organization_memberships', $request->getUri()->getPath()); + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('test_value', $query['before']); + $this->assertSame('test_value', $query['after']); + $this->assertArrayHasKey('limit', $query); + $this->assertSame('normal', $query['order']); + $this->assertSame('test_value', $query['permission_slug']); + $this->assertSame('direct', $query['assignment']); + } + + public function testListResources(): void + { + $fixture = $this->loadFixture('list_authorization_resource'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->listResources(before: 'test_value', after: 'test_value', limit: 1, order: \WorkOS\Resource\EventsOrder::Normal, organizationId: 'test_value', resourceTypeSlug: 'test_value', parentResourceId: 'test_value', parentResourceTypeSlug: 'test_value', parentExternalId: 'test_value', search: 'test_value'); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('authorization/resources', $request->getUri()->getPath()); + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('test_value', $query['before']); + $this->assertSame('test_value', $query['after']); + $this->assertArrayHasKey('limit', $query); + $this->assertSame('normal', $query['order']); + $this->assertSame('test_value', $query['organization_id']); + $this->assertSame('test_value', $query['resource_type_slug']); + $this->assertSame('test_value', $query['parent_resource_id']); + $this->assertSame('test_value', $query['parent_resource_type_slug']); + $this->assertSame('test_value', $query['parent_external_id']); + $this->assertSame('test_value', $query['search']); + } + + public function testCreateResource(): void + { + $fixture = $this->loadFixture('authorization_resource'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->createResource(externalId: 'test_value', name: 'test_value', resourceTypeSlug: 'test_value', organizationId: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\AuthorizationResource::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['name'], $result->name); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('authorization/resources', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['external_id']); + $this->assertSame('test_value', $body['name']); + $this->assertSame('test_value', $body['resource_type_slug']); + $this->assertSame('test_value', $body['organization_id']); + } + + public function testGetResource(): void + { + $fixture = $this->loadFixture('authorization_resource'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->getResource('test_resource_id'); + $this->assertInstanceOf(\WorkOS\Resource\AuthorizationResource::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['name'], $result->name); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('authorization/resources/test_resource_id', $request->getUri()->getPath()); + } + + public function testUpdateResource(): void + { + $fixture = $this->loadFixture('authorization_resource'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->updateResource('test_resource_id'); + $this->assertInstanceOf(\WorkOS\Resource\AuthorizationResource::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['name'], $result->name); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('PATCH', $request->getMethod()); + $this->assertStringEndsWith('authorization/resources/test_resource_id', $request->getUri()->getPath()); + } + + public function testDeleteResource(): void + { + $client = $this->createMockClient([['status' => 204]]); + $client->authorization()->deleteResource('test_resource_id'); + $request = $this->getLastRequest(); + $this->assertSame('DELETE', $request->getMethod()); + $this->assertStringEndsWith('authorization/resources/test_resource_id', $request->getUri()->getPath()); + } + + public function testListMembershipsForResource(): void + { + $fixture = $this->loadFixture('list_user_organization_membership_base_list_data'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->listMembershipsForResource('test_resource_id', before: 'test_value', after: 'test_value', limit: 1, order: \WorkOS\Resource\EventsOrder::Normal, permissionSlug: 'test_value', assignment: \WorkOS\Resource\AuthorizationAssignment::Direct); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('authorization/resources/test_resource_id/organization_memberships', $request->getUri()->getPath()); + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('test_value', $query['before']); + $this->assertSame('test_value', $query['after']); + $this->assertArrayHasKey('limit', $query); + $this->assertSame('normal', $query['order']); + $this->assertSame('test_value', $query['permission_slug']); + $this->assertSame('direct', $query['assignment']); + } + + public function testListEnvironmentRoles(): void + { + $fixture = $this->loadFixture('role_list'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->listEnvironmentRoles(); + $this->assertInstanceOf(\WorkOS\Resource\RoleList::class, $result); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('authorization/roles', $request->getUri()->getPath()); + } + + public function testCreateEnvironmentRole(): void + { + $fixture = $this->loadFixture('role'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->createEnvironmentRole(slug: 'test_value', name: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\Role::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['slug'], $result->slug); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('authorization/roles', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['slug']); + $this->assertSame('test_value', $body['name']); + } + + public function testGetEnvironmentRole(): void + { + $fixture = $this->loadFixture('role'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->getEnvironmentRole('test_slug'); + $this->assertInstanceOf(\WorkOS\Resource\Role::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['slug'], $result->slug); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('authorization/roles/test_slug', $request->getUri()->getPath()); + } + + public function testUpdateEnvironmentRole(): void + { + $fixture = $this->loadFixture('role'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->updateEnvironmentRole('test_slug'); + $this->assertInstanceOf(\WorkOS\Resource\Role::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['slug'], $result->slug); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('PATCH', $request->getMethod()); + $this->assertStringEndsWith('authorization/roles/test_slug', $request->getUri()->getPath()); + } + + public function testAddEnvironmentRolePermission(): void + { + $fixture = $this->loadFixture('role'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->addEnvironmentRolePermission('test_slug', bodySlug: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\Role::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['slug'], $result->slug); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('authorization/roles/test_slug/permissions', $request->getUri()->getPath()); + } + + public function testSetEnvironmentRolePermissions(): void + { + $fixture = $this->loadFixture('role'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->setEnvironmentRolePermissions('test_slug', permissions: []); + $this->assertInstanceOf(\WorkOS\Resource\Role::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['slug'], $result->slug); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('PUT', $request->getMethod()); + $this->assertStringEndsWith('authorization/roles/test_slug/permissions', $request->getUri()->getPath()); + } + + public function testListPermissions(): void + { + $fixture = $this->loadFixture('list_authorization_permission'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->listPermissions(before: 'test_value', after: 'test_value', limit: 1, order: \WorkOS\Resource\EventsOrder::Normal); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('authorization/permissions', $request->getUri()->getPath()); + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('test_value', $query['before']); + $this->assertSame('test_value', $query['after']); + $this->assertArrayHasKey('limit', $query); + $this->assertSame('normal', $query['order']); + } + + public function testCreatePermission(): void + { + $fixture = $this->loadFixture('permission'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->createPermission(slug: 'test_value', name: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\Permission::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['slug'], $result->slug); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('authorization/permissions', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['slug']); + $this->assertSame('test_value', $body['name']); + } + + public function testGetPermission(): void + { + $fixture = $this->loadFixture('authorization_permission'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->getPermission('test_slug'); + $this->assertInstanceOf(\WorkOS\Resource\AuthorizationPermission::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['slug'], $result->slug); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('authorization/permissions/test_slug', $request->getUri()->getPath()); + } + + public function testUpdatePermission(): void + { + $fixture = $this->loadFixture('authorization_permission'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->updatePermission('test_slug'); + $this->assertInstanceOf(\WorkOS\Resource\AuthorizationPermission::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['slug'], $result->slug); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('PATCH', $request->getMethod()); + $this->assertStringEndsWith('authorization/permissions/test_slug', $request->getUri()->getPath()); + } + + public function testDeletePermission(): void + { + $client = $this->createMockClient([['status' => 204]]); + $client->authorization()->deletePermission('test_slug'); + $request = $this->getLastRequest(); + $this->assertSame('DELETE', $request->getMethod()); + $this->assertStringEndsWith('authorization/permissions/test_slug', $request->getUri()->getPath()); + } + + public function testPaginationBoundary(): void + { + $fixture = $this->loadFixture('list_authorization_resource'); + // Ensure cursors are null (first/last page boundary) + $fixture['list_metadata']['before'] = null; + $fixture['list_metadata']['after'] = null; + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->authorization()->listOrganizationMembershipResources('test_organization_membership_id', permissionSlug: 'test_value'); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + // Verify cursors are null on boundary page + $this->assertNull($result->listMetadata['before']); + $this->assertNull($result->listMetadata['after']); + // Iterating should not throw on null cursors + foreach ($result as $item) { + $this->assertNotNull($item); + break; + } + } +} diff --git a/tests/Service/ConnectTest.php b/tests/Service/ConnectTest.php new file mode 100644 index 00000000..16bca0b1 --- /dev/null +++ b/tests/Service/ConnectTest.php @@ -0,0 +1,157 @@ +loadFixture('external_auth_complete_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->connect()->completeOAuth2(externalAuthId: 'test_value', user: \WorkOS\Resource\UserObject::fromArray($this->loadFixture('user_object'))); + $this->assertInstanceOf(\WorkOS\Resource\ExternalAuthCompleteResponse::class, $result); + $this->assertSame($fixture['redirect_uri'], $result->redirectUri); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('authkit/oauth2/complete', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['external_auth_id']); + } + + public function testListApplications(): void + { + $fixture = $this->loadFixture('list_connect_application'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->connect()->listApplications(before: 'test_value', after: 'test_value', limit: 1, order: \WorkOS\Resource\EventsOrder::Normal, organizationId: 'test_value'); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('connect/applications', $request->getUri()->getPath()); + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('test_value', $query['before']); + $this->assertSame('test_value', $query['after']); + $this->assertArrayHasKey('limit', $query); + $this->assertSame('normal', $query['order']); + $this->assertSame('test_value', $query['organization_id']); + } + + public function testGetApplication(): void + { + $fixture = $this->loadFixture('connect_application'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->connect()->getApplication('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\ConnectApplication::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['client_id'], $result->clientId); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('connect/applications/test_id', $request->getUri()->getPath()); + } + + public function testUpdateApplication(): void + { + $fixture = $this->loadFixture('connect_application'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->connect()->updateApplication('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\ConnectApplication::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['client_id'], $result->clientId); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('PUT', $request->getMethod()); + $this->assertStringEndsWith('connect/applications/test_id', $request->getUri()->getPath()); + } + + public function testDeleteApplication(): void + { + $client = $this->createMockClient([['status' => 204]]); + $client->connect()->deleteApplication('test_id'); + $request = $this->getLastRequest(); + $this->assertSame('DELETE', $request->getMethod()); + $this->assertStringEndsWith('connect/applications/test_id', $request->getUri()->getPath()); + } + + public function testListApplicationClientSecrets(): void + { + $fixture = $this->loadFixture('application_credentials_list_item'); + $client = $this->createMockClient([['status' => 200, 'body' => [$fixture]]]); + $result = $client->connect()->listApplicationClientSecrets('test_id'); + $this->assertIsArray($result); + $this->assertInstanceOf(\WorkOS\Resource\ApplicationCredentialsListItem::class, $result[0]); + $this->assertSame($fixture['id'], $result[0]->id); + $this->assertSame($fixture['secret_hint'], $result[0]->secretHint); + $this->assertIsArray($result[0]->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('connect/applications/test_id/client_secrets', $request->getUri()->getPath()); + } + + public function testCreateApplicationClientSecrets(): void + { + $fixture = $this->loadFixture('new_connect_application_secret'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->connect()->createApplicationClientSecrets('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\NewConnectApplicationSecret::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['secret_hint'], $result->secretHint); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('connect/applications/test_id/client_secrets', $request->getUri()->getPath()); + } + + public function testDeleteClientSecret(): void + { + $client = $this->createMockClient([['status' => 204]]); + $client->connect()->deleteClientSecret('test_id'); + $request = $this->getLastRequest(); + $this->assertSame('DELETE', $request->getMethod()); + $this->assertStringEndsWith('connect/client_secrets/test_id', $request->getUri()->getPath()); + } + + public function testCreateOAuthApplication(): void + { + $fixture = $this->loadFixture('connect_application'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->connect()->createOAuthApplication(name: 'test_value', isFirstParty: true); + $this->assertInstanceOf(\WorkOS\Resource\ConnectApplication::class, $result); + } + + public function testCreateM2MApplication(): void + { + $fixture = $this->loadFixture('connect_application'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->connect()->createM2MApplication(name: 'test_value', organizationId: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\ConnectApplication::class, $result); + } + + public function testPaginationBoundary(): void + { + $fixture = $this->loadFixture('list_connect_application'); + // Ensure cursors are null (first/last page boundary) + $fixture['list_metadata']['before'] = null; + $fixture['list_metadata']['after'] = null; + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->connect()->listApplications(); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + // Verify cursors are null on boundary page + $this->assertNull($result->listMetadata['before']); + $this->assertNull($result->listMetadata['after']); + // Iterating should not throw on null cursors + foreach ($result as $item) { + $this->assertNotNull($item); + break; + } + } +} diff --git a/tests/Service/DirectorySyncTest.php b/tests/Service/DirectorySyncTest.php new file mode 100644 index 00000000..63a33263 --- /dev/null +++ b/tests/Service/DirectorySyncTest.php @@ -0,0 +1,140 @@ +loadFixture('list_directory'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->directorySync()->listDirectories(before: 'test_value', after: 'test_value', limit: 1, order: \WorkOS\Resource\EventsOrder::Normal, organizationId: 'test_value', search: 'test_value', domain: 'test_value'); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('directories', $request->getUri()->getPath()); + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('test_value', $query['before']); + $this->assertSame('test_value', $query['after']); + $this->assertArrayHasKey('limit', $query); + $this->assertSame('normal', $query['order']); + $this->assertSame('test_value', $query['organization_id']); + $this->assertSame('test_value', $query['search']); + $this->assertSame('test_value', $query['domain']); + } + + public function testGetDirectory(): void + { + $fixture = $this->loadFixture('directory'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->directorySync()->getDirectory('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\Directory::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['organization_id'], $result->organizationId); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('directories/test_id', $request->getUri()->getPath()); + } + + public function testDeleteDirectory(): void + { + $client = $this->createMockClient([['status' => 204]]); + $client->directorySync()->deleteDirectory('test_id'); + $request = $this->getLastRequest(); + $this->assertSame('DELETE', $request->getMethod()); + $this->assertStringEndsWith('directories/test_id', $request->getUri()->getPath()); + } + + public function testListGroups(): void + { + $fixture = $this->loadFixture('list_directory_group'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->directorySync()->listGroups(before: 'test_value', after: 'test_value', limit: 1, order: \WorkOS\Resource\EventsOrder::Normal, directory: 'test_value', user: 'test_value'); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('directory_groups', $request->getUri()->getPath()); + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('test_value', $query['before']); + $this->assertSame('test_value', $query['after']); + $this->assertArrayHasKey('limit', $query); + $this->assertSame('normal', $query['order']); + $this->assertSame('test_value', $query['directory']); + $this->assertSame('test_value', $query['user']); + } + + public function testGetGroup(): void + { + $fixture = $this->loadFixture('directory_group'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->directorySync()->getGroup('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\DirectoryGroup::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['idp_id'], $result->idpId); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('directory_groups/test_id', $request->getUri()->getPath()); + } + + public function testListUsers(): void + { + $fixture = $this->loadFixture('list_directory_user_with_groups'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->directorySync()->listUsers(before: 'test_value', after: 'test_value', limit: 1, order: \WorkOS\Resource\EventsOrder::Normal, directory: 'test_value', group: 'test_value'); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('directory_users', $request->getUri()->getPath()); + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('test_value', $query['before']); + $this->assertSame('test_value', $query['after']); + $this->assertArrayHasKey('limit', $query); + $this->assertSame('normal', $query['order']); + $this->assertSame('test_value', $query['directory']); + $this->assertSame('test_value', $query['group']); + } + + public function testGetUser(): void + { + $fixture = $this->loadFixture('directory_user_with_groups'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->directorySync()->getUser('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\DirectoryUserWithGroups::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['directory_id'], $result->directoryId); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('directory_users/test_id', $request->getUri()->getPath()); + } + + public function testPaginationBoundary(): void + { + $fixture = $this->loadFixture('list_directory'); + // Ensure cursors are null (first/last page boundary) + $fixture['list_metadata']['before'] = null; + $fixture['list_metadata']['after'] = null; + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->directorySync()->listDirectories(); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + // Verify cursors are null on boundary page + $this->assertNull($result->listMetadata['before']); + $this->assertNull($result->listMetadata['after']); + // Iterating should not throw on null cursors + foreach ($result as $item) { + $this->assertNotNull($item); + break; + } + } +} diff --git a/tests/Service/EventsTest.php b/tests/Service/EventsTest.php new file mode 100644 index 00000000..f5f1c7af --- /dev/null +++ b/tests/Service/EventsTest.php @@ -0,0 +1,53 @@ +loadFixture('list_event_schema'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->events()->listEvents(before: 'test_value', after: 'test_value', limit: 1, order: \WorkOS\Resource\EventsOrder::Normal, events: [], rangeStart: 'test_value', rangeEnd: 'test_value', organizationId: 'test_value'); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('events', $request->getUri()->getPath()); + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('test_value', $query['before']); + $this->assertSame('test_value', $query['after']); + $this->assertArrayHasKey('limit', $query); + $this->assertSame('normal', $query['order']); + $this->assertSame('test_value', $query['range_start']); + $this->assertSame('test_value', $query['range_end']); + $this->assertSame('test_value', $query['organization_id']); + } + + public function testPaginationBoundary(): void + { + $fixture = $this->loadFixture('list_event_schema'); + // Ensure cursors are null (first/last page boundary) + $fixture['list_metadata']['before'] = null; + $fixture['list_metadata']['after'] = null; + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->events()->listEvents(); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + // Verify cursors are null on boundary page + $this->assertNull($result->listMetadata['before']); + $this->assertNull($result->listMetadata['after']); + // Iterating should not throw on null cursors + foreach ($result as $item) { + $this->assertNotNull($item); + break; + } + } +} diff --git a/tests/Service/FeatureFlagsTest.php b/tests/Service/FeatureFlagsTest.php new file mode 100644 index 00000000..bac5bc48 --- /dev/null +++ b/tests/Service/FeatureFlagsTest.php @@ -0,0 +1,142 @@ +loadFixture('list_flag'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->featureFlags()->listFeatureFlags(before: 'test_value', after: 'test_value', limit: 1, order: \WorkOS\Resource\EventsOrder::Normal); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('feature-flags', $request->getUri()->getPath()); + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('test_value', $query['before']); + $this->assertSame('test_value', $query['after']); + $this->assertArrayHasKey('limit', $query); + $this->assertSame('normal', $query['order']); + } + + public function testGetFeatureFlag(): void + { + $fixture = $this->loadFixture('flag'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->featureFlags()->getFeatureFlag('test_slug'); + $this->assertInstanceOf(\WorkOS\Resource\Flag::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['slug'], $result->slug); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('feature-flags/test_slug', $request->getUri()->getPath()); + } + + public function testDisableFeatureFlag(): void + { + $fixture = $this->loadFixture('feature_flag'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->featureFlags()->disableFeatureFlag('test_slug'); + $this->assertInstanceOf(\WorkOS\Resource\FeatureFlag::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['slug'], $result->slug); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('PUT', $request->getMethod()); + $this->assertStringEndsWith('feature-flags/test_slug/disable', $request->getUri()->getPath()); + } + + public function testEnableFeatureFlag(): void + { + $fixture = $this->loadFixture('feature_flag'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->featureFlags()->enableFeatureFlag('test_slug'); + $this->assertInstanceOf(\WorkOS\Resource\FeatureFlag::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['slug'], $result->slug); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('PUT', $request->getMethod()); + $this->assertStringEndsWith('feature-flags/test_slug/enable', $request->getUri()->getPath()); + } + + public function testAddFlagTarget(): void + { + $client = $this->createMockClient([['status' => 200, 'body' => []]]); + $client->featureFlags()->addFlagTarget('test_resourceId', 'test_slug'); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('feature-flags/test_slug/targets/test_resourceId', $request->getUri()->getPath()); + } + + public function testRemoveFlagTarget(): void + { + $client = $this->createMockClient([['status' => 204]]); + $client->featureFlags()->removeFlagTarget('test_resourceId', 'test_slug'); + $request = $this->getLastRequest(); + $this->assertSame('DELETE', $request->getMethod()); + $this->assertStringEndsWith('feature-flags/test_slug/targets/test_resourceId', $request->getUri()->getPath()); + } + + public function testListOrganizationFeatureFlags(): void + { + $fixture = $this->loadFixture('list_flag'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->featureFlags()->listOrganizationFeatureFlags('test_organizationId', before: 'test_value', after: 'test_value', limit: 1, order: \WorkOS\Resource\EventsOrder::Normal); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('organizations/test_organizationId/feature-flags', $request->getUri()->getPath()); + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('test_value', $query['before']); + $this->assertSame('test_value', $query['after']); + $this->assertArrayHasKey('limit', $query); + $this->assertSame('normal', $query['order']); + } + + public function testListUserFeatureFlags(): void + { + $fixture = $this->loadFixture('list_flag'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->featureFlags()->listUserFeatureFlags('test_userId', before: 'test_value', after: 'test_value', limit: 1, order: \WorkOS\Resource\EventsOrder::Normal); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('user_management/users/test_userId/feature-flags', $request->getUri()->getPath()); + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('test_value', $query['before']); + $this->assertSame('test_value', $query['after']); + $this->assertArrayHasKey('limit', $query); + $this->assertSame('normal', $query['order']); + } + + public function testPaginationBoundary(): void + { + $fixture = $this->loadFixture('list_flag'); + // Ensure cursors are null (first/last page boundary) + $fixture['list_metadata']['before'] = null; + $fixture['list_metadata']['after'] = null; + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->featureFlags()->listFeatureFlags(); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + // Verify cursors are null on boundary page + $this->assertNull($result->listMetadata['before']); + $this->assertNull($result->listMetadata['after']); + // Iterating should not throw on null cursors + foreach ($result as $item) { + $this->assertNotNull($item); + break; + } + } +} diff --git a/tests/Service/MultiFactorAuthTest.php b/tests/Service/MultiFactorAuthTest.php new file mode 100644 index 00000000..036f8fdd --- /dev/null +++ b/tests/Service/MultiFactorAuthTest.php @@ -0,0 +1,127 @@ +loadFixture('authentication_challenge_verify_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->multiFactorAuth()->verifyChallenge('test_id', code: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\AuthenticationChallengeVerifyResponse::class, $result); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('auth/challenges/test_id/verify', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['code']); + } + + public function testEnrollFactor(): void + { + $fixture = $this->loadFixture('authentication_factor_enrolled'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->multiFactorAuth()->enrollFactor(type: \WorkOS\Resource\AuthenticationFactorsCreateRequestType::GenericOtp); + $this->assertInstanceOf(\WorkOS\Resource\AuthenticationFactorEnrolled::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('auth/factors/enroll', $request->getUri()->getPath()); + } + + public function testGetFactor(): void + { + $fixture = $this->loadFixture('authentication_factor'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->multiFactorAuth()->getFactor('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\AuthenticationFactor::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('auth/factors/test_id', $request->getUri()->getPath()); + } + + public function testDeleteFactor(): void + { + $client = $this->createMockClient([['status' => 204]]); + $client->multiFactorAuth()->deleteFactor('test_id'); + $request = $this->getLastRequest(); + $this->assertSame('DELETE', $request->getMethod()); + $this->assertStringEndsWith('auth/factors/test_id', $request->getUri()->getPath()); + } + + public function testChallengeFactor(): void + { + $fixture = $this->loadFixture('authentication_challenge'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->multiFactorAuth()->challengeFactor('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\AuthenticationChallenge::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['authentication_factor_id'], $result->authenticationFactorId); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('auth/factors/test_id/challenge', $request->getUri()->getPath()); + } + + public function testListUserAuthFactors(): void + { + $fixture = $this->loadFixture('list_authentication_factor'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->multiFactorAuth()->listUserAuthFactors('test_userlandUserId', before: 'test_value', after: 'test_value', limit: 1, order: \WorkOS\Resource\EventsOrder::Normal); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('user_management/users/test_userlandUserId/auth_factors', $request->getUri()->getPath()); + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('test_value', $query['before']); + $this->assertSame('test_value', $query['after']); + $this->assertArrayHasKey('limit', $query); + $this->assertSame('normal', $query['order']); + } + + public function testCreateUserAuthFactors(): void + { + $fixture = $this->loadFixture('user_authentication_factor_enroll_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->multiFactorAuth()->createUserAuthFactors('test_userlandUserId', type: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\UserAuthenticationFactorEnrollResponse::class, $result); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('user_management/users/test_userlandUserId/auth_factors', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertArrayHasKey('type', $body); + } + + public function testPaginationBoundary(): void + { + $fixture = $this->loadFixture('list_authentication_factor'); + // Ensure cursors are null (first/last page boundary) + $fixture['list_metadata']['before'] = null; + $fixture['list_metadata']['after'] = null; + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->multiFactorAuth()->listUserAuthFactors('test_userlandUserId'); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + // Verify cursors are null on boundary page + $this->assertNull($result->listMetadata['before']); + $this->assertNull($result->listMetadata['after']); + // Iterating should not throw on null cursors + foreach ($result as $item) { + $this->assertNotNull($item); + break; + } + } +} diff --git a/tests/Service/OrganizationDomainsTest.php b/tests/Service/OrganizationDomainsTest.php new file mode 100644 index 00000000..bdd2a228 --- /dev/null +++ b/tests/Service/OrganizationDomainsTest.php @@ -0,0 +1,69 @@ +loadFixture('organization_domain'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->organizationDomains()->createOrganizationDomains(domain: 'test_value', organizationId: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\OrganizationDomain::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['organization_id'], $result->organizationId); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('organization_domains', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['domain']); + $this->assertSame('test_value', $body['organization_id']); + } + + public function testGetOrganizationDomain(): void + { + $fixture = $this->loadFixture('organization_domain_stand_alone'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->organizationDomains()->getOrganizationDomain('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\OrganizationDomainStandAlone::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['organization_id'], $result->organizationId); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('organization_domains/test_id', $request->getUri()->getPath()); + } + + public function testDeleteOrganizationDomain(): void + { + $client = $this->createMockClient([['status' => 204]]); + $client->organizationDomains()->deleteOrganizationDomain('test_id'); + $request = $this->getLastRequest(); + $this->assertSame('DELETE', $request->getMethod()); + $this->assertStringEndsWith('organization_domains/test_id', $request->getUri()->getPath()); + } + + public function testVerifyOrganizationDomain(): void + { + $fixture = $this->loadFixture('organization_domain_stand_alone'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->organizationDomains()->verifyOrganizationDomain('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\OrganizationDomainStandAlone::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['organization_id'], $result->organizationId); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('organization_domains/test_id/verify', $request->getUri()->getPath()); + } +} diff --git a/tests/Service/OrganizationsTest.php b/tests/Service/OrganizationsTest.php new file mode 100644 index 00000000..ef12667f --- /dev/null +++ b/tests/Service/OrganizationsTest.php @@ -0,0 +1,131 @@ +loadFixture('list_organization'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->organizations()->listOrganizations(before: 'test_value', after: 'test_value', limit: 1, order: \WorkOS\Resource\EventsOrder::Normal, domains: [], search: 'test_value'); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('organizations', $request->getUri()->getPath()); + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('test_value', $query['before']); + $this->assertSame('test_value', $query['after']); + $this->assertArrayHasKey('limit', $query); + $this->assertSame('normal', $query['order']); + $this->assertSame('test_value', $query['search']); + } + + public function testCreateOrganization(): void + { + $fixture = $this->loadFixture('organization'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->organizations()->createOrganization(name: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\Organization::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['name'], $result->name); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('organizations', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['name']); + } + + public function testGetOrganizationByExternalId(): void + { + $fixture = $this->loadFixture('organization'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->organizations()->getOrganizationByExternalId('test_external_id'); + $this->assertInstanceOf(\WorkOS\Resource\Organization::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['name'], $result->name); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('organizations/external_id/test_external_id', $request->getUri()->getPath()); + } + + public function testGetOrganization(): void + { + $fixture = $this->loadFixture('organization'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->organizations()->getOrganization('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\Organization::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['name'], $result->name); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('organizations/test_id', $request->getUri()->getPath()); + } + + public function testUpdateOrganization(): void + { + $fixture = $this->loadFixture('organization'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->organizations()->updateOrganization('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\Organization::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['name'], $result->name); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('PUT', $request->getMethod()); + $this->assertStringEndsWith('organizations/test_id', $request->getUri()->getPath()); + } + + public function testDeleteOrganization(): void + { + $client = $this->createMockClient([['status' => 204]]); + $client->organizations()->deleteOrganization('test_id'); + $request = $this->getLastRequest(); + $this->assertSame('DELETE', $request->getMethod()); + $this->assertStringEndsWith('organizations/test_id', $request->getUri()->getPath()); + } + + public function testListOrganizationAuditLogConfiguration(): void + { + $fixture = $this->loadFixture('audit_log_configuration'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->organizations()->listOrganizationAuditLogConfiguration('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\AuditLogConfiguration::class, $result); + $this->assertSame($fixture['organization_id'], $result->organizationId); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('organizations/test_id/audit_log_configuration', $request->getUri()->getPath()); + } + + public function testPaginationBoundary(): void + { + $fixture = $this->loadFixture('list_organization'); + // Ensure cursors are null (first/last page boundary) + $fixture['list_metadata']['before'] = null; + $fixture['list_metadata']['after'] = null; + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->organizations()->listOrganizations(); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + // Verify cursors are null on boundary page + $this->assertNull($result->listMetadata['before']); + $this->assertNull($result->listMetadata['after']); + // Iterating should not throw on null cursors + foreach ($result as $item) { + $this->assertNotNull($item); + break; + } + } +} diff --git a/tests/Service/PipesTest.php b/tests/Service/PipesTest.php new file mode 100644 index 00000000..9f155a74 --- /dev/null +++ b/tests/Service/PipesTest.php @@ -0,0 +1,79 @@ +loadFixture('data_integration_authorize_url_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->pipes()->authorizeDataIntegration('test_slug', userId: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\DataIntegrationAuthorizeUrlResponse::class, $result); + $this->assertSame($fixture['url'], $result->url); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('data-integrations/test_slug/authorize', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['user_id']); + } + + public function testCreateDataIntegrationToken(): void + { + $fixture = $this->loadFixture('data_integration_access_token_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->pipes()->createDataIntegrationToken('test_slug', userId: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\DataIntegrationAccessTokenResponse::class, $result); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('data-integrations/test_slug/token', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['user_id']); + } + + public function testGetUserConnectedAccount(): void + { + $fixture = $this->loadFixture('connected_account'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->pipes()->getUserConnectedAccount('test_user_id', 'test_slug'); + $this->assertInstanceOf(\WorkOS\Resource\ConnectedAccount::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['created_at'], $result->createdAt); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('user_management/users/test_user_id/connected_accounts/test_slug', $request->getUri()->getPath()); + } + + public function testDeleteUserConnectedAccount(): void + { + $client = $this->createMockClient([['status' => 204]]); + $client->pipes()->deleteUserConnectedAccount('test_user_id', 'test_slug'); + $request = $this->getLastRequest(); + $this->assertSame('DELETE', $request->getMethod()); + $this->assertStringEndsWith('user_management/users/test_user_id/connected_accounts/test_slug', $request->getUri()->getPath()); + } + + public function testListUserDataProviders(): void + { + $fixture = $this->loadFixture('data_integrations_list_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->pipes()->listUserDataProviders('test_user_id'); + $this->assertInstanceOf(\WorkOS\Resource\DataIntegrationsListResponse::class, $result); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('user_management/users/test_user_id/data_providers', $request->getUri()->getPath()); + } +} diff --git a/tests/Service/RadarTest.php b/tests/Service/RadarTest.php new file mode 100644 index 00000000..baa95a31 --- /dev/null +++ b/tests/Service/RadarTest.php @@ -0,0 +1,67 @@ +loadFixture('radar_standalone_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->radar()->createAttempts(ipAddress: 'test_value', userAgent: 'test_value', email: 'test_value', authMethod: \WorkOS\Resource\RadarStandaloneAssessRequestAuthMethod::Password, action: \WorkOS\Resource\RadarStandaloneAssessRequestAction::Login); + $this->assertInstanceOf(\WorkOS\Resource\RadarStandaloneResponse::class, $result); + $this->assertSame($fixture['reason'], $result->reason); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('radar/attempts', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['ip_address']); + $this->assertSame('test_value', $body['user_agent']); + $this->assertSame('test_value', $body['email']); + } + + public function testUpdateAttempt(): void + { + $client = $this->createMockClient([['status' => 200, 'body' => []]]); + $client->radar()->updateAttempt('test_id'); + $request = $this->getLastRequest(); + $this->assertSame('PUT', $request->getMethod()); + $this->assertStringEndsWith('radar/attempts/test_id', $request->getUri()->getPath()); + } + + public function testAddListEntry(): void + { + $fixture = $this->loadFixture('radar_list_entry_already_present_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->radar()->addListEntry(\WorkOS\Resource\RadarType::IpAddress, \WorkOS\Resource\RadarAction::Block, entry: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\RadarListEntryAlreadyPresentResponse::class, $result); + $this->assertSame($fixture['message'], $result->message); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('radar/lists/ip_address/block', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['entry']); + } + + public function testRemoveListEntry(): void + { + $client = $this->createMockClient([['status' => 204]]); + $client->radar()->removeListEntry(\WorkOS\Resource\RadarType::IpAddress, \WorkOS\Resource\RadarAction::Block, entry: 'test_value'); + $request = $this->getLastRequest(); + $this->assertSame('DELETE', $request->getMethod()); + $this->assertStringEndsWith('radar/lists/ip_address/block', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['entry']); + } +} diff --git a/tests/Service/RuntimeBehaviorTest.php b/tests/Service/RuntimeBehaviorTest.php new file mode 100644 index 00000000..aabb1442 --- /dev/null +++ b/tests/Service/RuntimeBehaviorTest.php @@ -0,0 +1,151 @@ +loadFixture('organization'); + $second = $this->loadFixture('organization'); + $third = $this->loadFixture('organization'); + + $first['id'] = 'org_first'; + $second['id'] = 'org_second'; + $third['id'] = 'org_third'; + + $client = $this->createMockClient([ + [ + 'status' => 200, + 'body' => [ + 'data' => [$first, $second], + 'list_metadata' => ['after' => 'cursor_next'], + ], + ], + [ + 'status' => 200, + 'body' => [ + 'data' => [$third], + 'list_metadata' => ['after' => null], + ], + ], + ]); + + $page = $client->organizations()->listOrganizations(); + $ids = array_map( + static fn ($organization) => $organization->id, + iterator_to_array($page->autoPagingIterator(), false), + ); + + $this->assertSame(['org_first', 'org_second', 'org_third'], $ids); + $this->assertSame('after=cursor_next', $this->getLastRequest()->getUri()->getQuery()); + } + + public function testPerRequestOverridesAffectTransport(): void + { + $client = $this->createMockClient( + [['status' => 200, 'body' => $this->loadFixture('organization')]], + baseUrl: 'https://api.primary.example', + ); + + $client->organizations()->getOrganization( + 'org_123', + new RequestOptions( + extraHeaders: ['X-Test-Header' => 'override'], + timeout: 12, + baseUrl: 'https://api.override.example/v1', + ), + ); + + $request = $this->getLastRequest(); + $requestOptions = $this->getLastRequestOptions(); + + $this->assertSame('api.override.example', $request->getUri()->getHost()); + $this->assertSame('/v1/organizations/org_123', $request->getUri()->getPath()); + $this->assertSame('override', $request->getHeaderLine('X-Test-Header')); + $this->assertSame(12, $requestOptions['timeout']); + } + + public function testWrapperMethodsUseInstanceScopedCredentials(): void + { + $fixture = $this->loadFixture('authenticate_response'); + + $clientA = $this->createMockClient( + [['status' => 200, 'body' => $fixture]], + apiKey: 'api_key_a', + clientId: 'client_a', + ); + $clientA->userManagement()->authenticateWithPassword(email: 'a@example.com', password: 'secret'); + $requestBodyA = json_decode((string) $this->getLastRequest()->getBody(), true); + + $clientB = $this->createMockClient( + [['status' => 200, 'body' => $fixture]], + apiKey: 'api_key_b', + clientId: 'client_b', + ); + $clientB->userManagement()->authenticateWithPassword(email: 'b@example.com', password: 'secret'); + $requestBodyB = json_decode((string) $this->getLastRequest()->getBody(), true); + + $this->assertSame('client_a', $requestBodyA['client_id']); + $this->assertSame('api_key_a', $requestBodyA['client_secret']); + $this->assertSame('client_b', $requestBodyB['client_id']); + $this->assertSame('api_key_b', $requestBodyB['client_secret']); + } + + public function testAuthenticationErrorsAreMapped(): void + { + $client = $this->createMockClient([ + [ + 'status' => 401, + 'headers' => ['X-Request-ID' => 'req_auth'], + 'body' => ['message' => 'Nope'], + ], + ]); + + try { + $client->organizations()->getOrganization( + 'org_123', + new RequestOptions(maxRetries: 0), + ); + $this->fail('Expected AuthenticationException'); + } catch (AuthenticationException $exception) { + $this->assertSame(401, $exception->statusCode); + $this->assertSame('req_auth', $exception->requestId); + $this->assertSame('Nope', $exception->getMessage()); + } + } + + public function testRateLimitErrorsExposeRetryAfter(): void + { + $client = $this->createMockClient([ + [ + 'status' => 429, + 'headers' => [ + 'X-Request-ID' => 'req_rate', + 'Retry-After' => '7', + ], + 'body' => ['message' => 'Slow down'], + ], + ]); + + try { + $client->organizations()->listOrganizations(options: new RequestOptions(maxRetries: 0)); + $this->fail('Expected RateLimitExceededException'); + } catch (RateLimitExceededException $exception) { + $this->assertSame(429, $exception->statusCode); + $this->assertSame('req_rate', $exception->requestId); + $this->assertSame('Slow down', $exception->getMessage()); + $this->assertSame(7, $exception->retryAfter); + } + } +} diff --git a/tests/Service/SSOTest.php b/tests/Service/SSOTest.php new file mode 100644 index 00000000..312a8d5f --- /dev/null +++ b/tests/Service/SSOTest.php @@ -0,0 +1,142 @@ +loadFixture('list_connection'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->sso()->listConnections(before: 'test_value', after: 'test_value', limit: 1, order: \WorkOS\Resource\EventsOrder::Normal, connectionType: \WorkOS\Resource\ConnectionsConnectionType::Adfssaml, domain: 'test_value', organizationId: 'test_value', search: 'test_value'); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('connections', $request->getUri()->getPath()); + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('test_value', $query['before']); + $this->assertSame('test_value', $query['after']); + $this->assertArrayHasKey('limit', $query); + $this->assertSame('normal', $query['order']); + $this->assertSame('ADFSSAML', $query['connection_type']); + $this->assertSame('test_value', $query['domain']); + $this->assertSame('test_value', $query['organization_id']); + $this->assertSame('test_value', $query['search']); + } + + public function testGetConnection(): void + { + $fixture = $this->loadFixture('connection'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->sso()->getConnection('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\Connection::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['name'], $result->name); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('connections/test_id', $request->getUri()->getPath()); + } + + public function testDeleteConnection(): void + { + $client = $this->createMockClient([['status' => 204]]); + $client->sso()->deleteConnection('test_id'); + $request = $this->getLastRequest(); + $this->assertSame('DELETE', $request->getMethod()); + $this->assertStringEndsWith('connections/test_id', $request->getUri()->getPath()); + } + + public function testGetAuthorizationUrl(): void + { + $fixture = $this->loadFixture('sso_authorize_url_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->sso()->getAuthorizationUrl(redirectUri: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\SSOAuthorizeUrlResponse::class, $result); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('sso/authorize', $request->getUri()->getPath()); + } + + public function testGetLogoutUrl(): void + { + $client = $this->createMockClient([['status' => 200, 'body' => []]]); + $client->sso()->getLogoutUrl(token: 'test_value'); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('sso/logout', $request->getUri()->getPath()); + } + + public function testAuthorizeLogout(): void + { + $fixture = $this->loadFixture('sso_logout_authorize_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->sso()->authorizeLogout(profileId: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\SSOLogoutAuthorizeResponse::class, $result); + $this->assertSame($fixture['logout_url'], $result->logoutUrl); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('sso/logout/authorize', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['profile_id']); + } + + public function testGetProfile(): void + { + $fixture = $this->loadFixture('profile'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->sso()->getProfile(); + $this->assertInstanceOf(\WorkOS\Resource\Profile::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['connection_id'], $result->connectionId); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('sso/profile', $request->getUri()->getPath()); + } + + public function testGetProfileAndToken(): void + { + $fixture = $this->loadFixture('sso_token_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->sso()->getProfileAndToken(code: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\SSOTokenResponse::class, $result); + $this->assertSame($fixture['access_token'], $result->accessToken); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('sso/token', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['code']); + } + + public function testPaginationBoundary(): void + { + $fixture = $this->loadFixture('list_connection'); + // Ensure cursors are null (first/last page boundary) + $fixture['list_metadata']['before'] = null; + $fixture['list_metadata']['after'] = null; + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->sso()->listConnections(); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + // Verify cursors are null on boundary page + $this->assertNull($result->listMetadata['before']); + $this->assertNull($result->listMetadata['after']); + // Iterating should not throw on null cursors + foreach ($result as $item) { + $this->assertNotNull($item); + break; + } + } +} diff --git a/tests/Service/UserManagementTest.php b/tests/Service/UserManagementTest.php new file mode 100644 index 00000000..b18065b0 --- /dev/null +++ b/tests/Service/UserManagementTest.php @@ -0,0 +1,688 @@ +loadFixture('jwks_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->getJwks('test_clientId'); + $this->assertInstanceOf(\WorkOS\Resource\JwksResponse::class, $result); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('sso/jwks/test_clientId', $request->getUri()->getPath()); + } + + public function testGetAuthorizationUrl(): void + { + $client = $this->createMockClient([['status' => 200, 'body' => []]]); + $client->userManagement()->getAuthorizationUrl(redirectUri: 'test_value'); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('user_management/authorize', $request->getUri()->getPath()); + } + + public function testCreateDevice(): void + { + $fixture = $this->loadFixture('device_authorization_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->createDevice(clientId: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\DeviceAuthorizationResponse::class, $result); + $this->assertSame($fixture['device_code'], $result->deviceCode); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('user_management/authorize/device', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['client_id']); + } + + public function testGetLogoutUrl(): void + { + $client = $this->createMockClient([['status' => 200, 'body' => []]]); + $client->userManagement()->getLogoutUrl(sessionId: 'test_value'); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('user_management/sessions/logout', $request->getUri()->getPath()); + } + + public function testRevokeSession(): void + { + $client = $this->createMockClient([['status' => 200, 'body' => []]]); + $client->userManagement()->revokeSession(sessionId: 'test_value'); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('user_management/sessions/revoke', $request->getUri()->getPath()); + } + + public function testCreateCorsOrigin(): void + { + $fixture = $this->loadFixture('cors_origin_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->createCorsOrigin(origin: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\CORSOriginResponse::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['origin'], $result->origin); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('user_management/cors_origins', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['origin']); + } + + public function testGetEmailVerification(): void + { + $fixture = $this->loadFixture('email_verification'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->getEmailVerification('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\EmailVerification::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['user_id'], $result->userId); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('user_management/email_verification/test_id', $request->getUri()->getPath()); + } + + public function testResetPassword(): void + { + $fixture = $this->loadFixture('password_reset'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->resetPassword(email: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\PasswordReset::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['user_id'], $result->userId); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('user_management/password_reset', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['email']); + } + + public function testConfirmPasswordReset(): void + { + $fixture = $this->loadFixture('reset_password_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->confirmPasswordReset(token: 'test_value', newPassword: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\ResetPasswordResponse::class, $result); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('user_management/password_reset/confirm', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['token']); + $this->assertSame('test_value', $body['new_password']); + } + + public function testGetPasswordReset(): void + { + $fixture = $this->loadFixture('password_reset'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->getPasswordReset('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\PasswordReset::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['user_id'], $result->userId); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('user_management/password_reset/test_id', $request->getUri()->getPath()); + } + + public function testListUsers(): void + { + $fixture = $this->loadFixture('list_user'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->listUsers(before: 'test_value', after: 'test_value', limit: 1, order: \WorkOS\Resource\EventsOrder::Normal, organization: 'test_value', organizationId: 'test_value', email: 'test_value'); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('user_management/users', $request->getUri()->getPath()); + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('test_value', $query['before']); + $this->assertSame('test_value', $query['after']); + $this->assertArrayHasKey('limit', $query); + $this->assertSame('normal', $query['order']); + $this->assertSame('test_value', $query['organization']); + $this->assertSame('test_value', $query['organization_id']); + $this->assertSame('test_value', $query['email']); + } + + public function testCreateUser(): void + { + $fixture = $this->loadFixture('user'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->createUser(email: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\User::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['email'], $result->email); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('user_management/users', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['email']); + } + + public function testGetUserByExternalId(): void + { + $fixture = $this->loadFixture('user'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->getUserByExternalId('test_external_id'); + $this->assertInstanceOf(\WorkOS\Resource\User::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['email'], $result->email); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('user_management/users/external_id/test_external_id', $request->getUri()->getPath()); + } + + public function testGetUser(): void + { + $fixture = $this->loadFixture('user'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->getUser('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\User::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['email'], $result->email); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('user_management/users/test_id', $request->getUri()->getPath()); + } + + public function testUpdateUser(): void + { + $fixture = $this->loadFixture('user'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->updateUser('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\User::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['email'], $result->email); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('PUT', $request->getMethod()); + $this->assertStringEndsWith('user_management/users/test_id', $request->getUri()->getPath()); + } + + public function testDeleteUser(): void + { + $client = $this->createMockClient([['status' => 204]]); + $client->userManagement()->deleteUser('test_id'); + $request = $this->getLastRequest(); + $this->assertSame('DELETE', $request->getMethod()); + $this->assertStringEndsWith('user_management/users/test_id', $request->getUri()->getPath()); + } + + public function testConfirmEmailChange(): void + { + $fixture = $this->loadFixture('email_change_confirmation'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->confirmEmailChange('test_id', code: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\EmailChangeConfirmation::class, $result); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('user_management/users/test_id/email_change/confirm', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['code']); + } + + public function testSendEmailChange(): void + { + $fixture = $this->loadFixture('email_change'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->sendEmailChange('test_id', newEmail: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\EmailChange::class, $result); + $this->assertSame($fixture['new_email'], $result->newEmail); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('user_management/users/test_id/email_change/send', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['new_email']); + } + + public function testVerifyEmail(): void + { + $fixture = $this->loadFixture('verify_email_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->verifyEmail('test_id', code: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\VerifyEmailResponse::class, $result); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('user_management/users/test_id/email_verification/confirm', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['code']); + } + + public function testSendVerificationEmail(): void + { + $fixture = $this->loadFixture('send_verification_email_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->sendVerificationEmail('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\SendVerificationEmailResponse::class, $result); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('user_management/users/test_id/email_verification/send', $request->getUri()->getPath()); + } + + public function testGetUserIdentities(): void + { + $fixture = $this->loadFixture('user_identities_get_item'); + $client = $this->createMockClient([['status' => 200, 'body' => [$fixture]]]); + $result = $client->userManagement()->getUserIdentities('test_id'); + $this->assertIsArray($result); + $this->assertInstanceOf(\WorkOS\Resource\UserIdentitiesGetItem::class, $result[0]); + $this->assertSame($fixture['idp_id'], $result[0]->idpId); + $this->assertIsArray($result[0]->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('user_management/users/test_id/identities', $request->getUri()->getPath()); + } + + public function testListSessions(): void + { + $fixture = $this->loadFixture('list_user_sessions_list_item'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->listSessions('test_id', before: 'test_value', after: 'test_value', limit: 1, order: \WorkOS\Resource\EventsOrder::Normal); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('user_management/users/test_id/sessions', $request->getUri()->getPath()); + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('test_value', $query['before']); + $this->assertSame('test_value', $query['after']); + $this->assertArrayHasKey('limit', $query); + $this->assertSame('normal', $query['order']); + } + + public function testListInvitations(): void + { + $fixture = $this->loadFixture('list_user_invite'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->listInvitations(before: 'test_value', after: 'test_value', limit: 1, order: \WorkOS\Resource\EventsOrder::Normal, organizationId: 'test_value', email: 'test_value'); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('user_management/invitations', $request->getUri()->getPath()); + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('test_value', $query['before']); + $this->assertSame('test_value', $query['after']); + $this->assertArrayHasKey('limit', $query); + $this->assertSame('normal', $query['order']); + $this->assertSame('test_value', $query['organization_id']); + $this->assertSame('test_value', $query['email']); + } + + public function testSendInvitation(): void + { + $fixture = $this->loadFixture('user_invite'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->sendInvitation(email: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\UserInvite::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['email'], $result->email); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('user_management/invitations', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['email']); + } + + public function testFindInvitationByToken(): void + { + $fixture = $this->loadFixture('user_invite'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->findInvitationByToken('test_token'); + $this->assertInstanceOf(\WorkOS\Resource\UserInvite::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['email'], $result->email); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('user_management/invitations/by_token/test_token', $request->getUri()->getPath()); + } + + public function testGetInvitation(): void + { + $fixture = $this->loadFixture('user_invite'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->getInvitation('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\UserInvite::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['email'], $result->email); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('user_management/invitations/test_id', $request->getUri()->getPath()); + } + + public function testAcceptInvitation(): void + { + $fixture = $this->loadFixture('invitation'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->acceptInvitation('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\Invitation::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['email'], $result->email); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('user_management/invitations/test_id/accept', $request->getUri()->getPath()); + } + + public function testResendInvitation(): void + { + $fixture = $this->loadFixture('user_invite'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->resendInvitation('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\UserInvite::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['email'], $result->email); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('user_management/invitations/test_id/resend', $request->getUri()->getPath()); + } + + public function testRevokeInvitation(): void + { + $fixture = $this->loadFixture('invitation'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->revokeInvitation('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\Invitation::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['email'], $result->email); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('user_management/invitations/test_id/revoke', $request->getUri()->getPath()); + } + + public function testUpdateJWTTemplate(): void + { + $fixture = $this->loadFixture('jwt_template_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->updateJWTTemplate(content: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\JWTTemplateResponse::class, $result); + $this->assertSame($fixture['content'], $result->content); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('PUT', $request->getMethod()); + $this->assertStringEndsWith('user_management/jwt_template', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['content']); + } + + public function testCreateMagicAuth(): void + { + $fixture = $this->loadFixture('magic_auth'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->createMagicAuth(email: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\MagicAuth::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['user_id'], $result->userId); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('user_management/magic_auth', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['email']); + } + + public function testGetMagicAuth(): void + { + $fixture = $this->loadFixture('magic_auth'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->getMagicAuth('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\MagicAuth::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['user_id'], $result->userId); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('user_management/magic_auth/test_id', $request->getUri()->getPath()); + } + + public function testListOrganizationMemberships(): void + { + $fixture = $this->loadFixture('list_user_organization_membership'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->listOrganizationMemberships(before: 'test_value', after: 'test_value', limit: 1, order: \WorkOS\Resource\EventsOrder::Normal, organizationId: 'test_value', statuses: [], userId: 'test_value'); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('user_management/organization_memberships', $request->getUri()->getPath()); + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('test_value', $query['before']); + $this->assertSame('test_value', $query['after']); + $this->assertArrayHasKey('limit', $query); + $this->assertSame('normal', $query['order']); + $this->assertSame('test_value', $query['organization_id']); + $this->assertSame('test_value', $query['user_id']); + } + + public function testCreateOrganizationMembership(): void + { + $fixture = $this->loadFixture('organization_membership'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->createOrganizationMembership(userId: 'test_value', organizationId: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\OrganizationMembership::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['user_id'], $result->userId); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('user_management/organization_memberships', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['user_id']); + $this->assertSame('test_value', $body['organization_id']); + } + + public function testGetOrganizationMembership(): void + { + $fixture = $this->loadFixture('user_organization_membership'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->getOrganizationMembership('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\UserOrganizationMembership::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['user_id'], $result->userId); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('user_management/organization_memberships/test_id', $request->getUri()->getPath()); + } + + public function testUpdateOrganizationMembership(): void + { + $fixture = $this->loadFixture('user_organization_membership'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->updateOrganizationMembership('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\UserOrganizationMembership::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['user_id'], $result->userId); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('PUT', $request->getMethod()); + $this->assertStringEndsWith('user_management/organization_memberships/test_id', $request->getUri()->getPath()); + } + + public function testDeleteOrganizationMembership(): void + { + $client = $this->createMockClient([['status' => 204]]); + $client->userManagement()->deleteOrganizationMembership('test_id'); + $request = $this->getLastRequest(); + $this->assertSame('DELETE', $request->getMethod()); + $this->assertStringEndsWith('user_management/organization_memberships/test_id', $request->getUri()->getPath()); + } + + public function testDeactivateOrganizationMembership(): void + { + $fixture = $this->loadFixture('organization_membership'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->deactivateOrganizationMembership('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\OrganizationMembership::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['user_id'], $result->userId); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('PUT', $request->getMethod()); + $this->assertStringEndsWith('user_management/organization_memberships/test_id/deactivate', $request->getUri()->getPath()); + } + + public function testReactivateOrganizationMembership(): void + { + $fixture = $this->loadFixture('user_organization_membership'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->reactivateOrganizationMembership('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\UserOrganizationMembership::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['user_id'], $result->userId); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('PUT', $request->getMethod()); + $this->assertStringEndsWith('user_management/organization_memberships/test_id/reactivate', $request->getUri()->getPath()); + } + + public function testCreateRedirectUri(): void + { + $fixture = $this->loadFixture('redirect_uri'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->createRedirectUri(uri: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\RedirectUri::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['uri'], $result->uri); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('user_management/redirect_uris', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['uri']); + } + + public function testListUserAuthorizedApplications(): void + { + $fixture = $this->loadFixture('list_authorized_connect_application_list_data'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->listUserAuthorizedApplications('test_user_id', before: 'test_value', after: 'test_value', limit: 1, order: \WorkOS\Resource\EventsOrder::Normal); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('user_management/users/test_user_id/authorized_applications', $request->getUri()->getPath()); + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('test_value', $query['before']); + $this->assertSame('test_value', $query['after']); + $this->assertArrayHasKey('limit', $query); + $this->assertSame('normal', $query['order']); + } + + public function testDeleteUserAuthorizedApplication(): void + { + $client = $this->createMockClient([['status' => 204]]); + $client->userManagement()->deleteUserAuthorizedApplication('test_application_id', 'test_user_id'); + $request = $this->getLastRequest(); + $this->assertSame('DELETE', $request->getMethod()); + $this->assertStringEndsWith('user_management/users/test_user_id/authorized_applications/test_application_id', $request->getUri()->getPath()); + } + + public function testAuthenticateWithPassword(): void + { + $fixture = $this->loadFixture('authenticate_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->authenticateWithPassword(email: 'test_value', password: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\AuthenticateResponse::class, $result); + } + + public function testAuthenticateWithCode(): void + { + $fixture = $this->loadFixture('authenticate_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->authenticateWithCode(); + $this->assertInstanceOf(\WorkOS\Resource\AuthenticateResponse::class, $result); + } + + public function testAuthenticateWithRefreshToken(): void + { + $fixture = $this->loadFixture('authenticate_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->authenticateWithRefreshToken(refreshToken: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\AuthenticateResponse::class, $result); + } + + public function testAuthenticateWithMagicAuth(): void + { + $fixture = $this->loadFixture('authenticate_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->authenticateWithMagicAuth(); + $this->assertInstanceOf(\WorkOS\Resource\AuthenticateResponse::class, $result); + } + + public function testAuthenticateWithEmailVerification(): void + { + $fixture = $this->loadFixture('authenticate_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->authenticateWithEmailVerification(); + $this->assertInstanceOf(\WorkOS\Resource\AuthenticateResponse::class, $result); + } + + public function testAuthenticateWithTotp(): void + { + $fixture = $this->loadFixture('authenticate_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->authenticateWithTotp(); + $this->assertInstanceOf(\WorkOS\Resource\AuthenticateResponse::class, $result); + } + + public function testAuthenticateWithOrganizationSelection(): void + { + $fixture = $this->loadFixture('authenticate_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->authenticateWithOrganizationSelection(); + $this->assertInstanceOf(\WorkOS\Resource\AuthenticateResponse::class, $result); + } + + public function testAuthenticateWithDeviceCode(): void + { + $fixture = $this->loadFixture('authenticate_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->authenticateWithDeviceCode(); + $this->assertInstanceOf(\WorkOS\Resource\AuthenticateResponse::class, $result); + } + + public function testPaginationBoundary(): void + { + $fixture = $this->loadFixture('list_user'); + // Ensure cursors are null (first/last page boundary) + $fixture['list_metadata']['before'] = null; + $fixture['list_metadata']['after'] = null; + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->userManagement()->listUsers(); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + // Verify cursors are null on boundary page + $this->assertNull($result->listMetadata['before']); + $this->assertNull($result->listMetadata['after']); + // Iterating should not throw on null cursors + foreach ($result as $item) { + $this->assertNotNull($item); + break; + } + } +} diff --git a/tests/Service/WebhooksTest.php b/tests/Service/WebhooksTest.php new file mode 100644 index 00000000..3b450970 --- /dev/null +++ b/tests/Service/WebhooksTest.php @@ -0,0 +1,89 @@ +loadFixture('list_webhook_endpoint_json'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->webhooks()->listWebhookEndpoints(before: 'test_value', after: 'test_value', limit: 1, order: \WorkOS\Resource\EventsOrder::Normal); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('webhook_endpoints', $request->getUri()->getPath()); + parse_str($request->getUri()->getQuery(), $query); + $this->assertSame('test_value', $query['before']); + $this->assertSame('test_value', $query['after']); + $this->assertArrayHasKey('limit', $query); + $this->assertSame('normal', $query['order']); + } + + public function testCreateWebhookEndpoints(): void + { + $fixture = $this->loadFixture('webhook_endpoint_json'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->webhooks()->createWebhookEndpoints(endpointUrl: 'test_value', events: []); + $this->assertInstanceOf(\WorkOS\Resource\WebhookEndpointJson::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['endpoint_url'], $result->endpointUrl); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('webhook_endpoints', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['endpoint_url']); + } + + public function testUpdateWebhookEndpoint(): void + { + $fixture = $this->loadFixture('webhook_endpoint_json'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->webhooks()->updateWebhookEndpoint('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\WebhookEndpointJson::class, $result); + $this->assertSame($fixture['id'], $result->id); + $this->assertSame($fixture['endpoint_url'], $result->endpointUrl); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('PATCH', $request->getMethod()); + $this->assertStringEndsWith('webhook_endpoints/test_id', $request->getUri()->getPath()); + } + + public function testDeleteWebhookEndpoint(): void + { + $client = $this->createMockClient([['status' => 204]]); + $client->webhooks()->deleteWebhookEndpoint('test_id'); + $request = $this->getLastRequest(); + $this->assertSame('DELETE', $request->getMethod()); + $this->assertStringEndsWith('webhook_endpoints/test_id', $request->getUri()->getPath()); + } + + public function testPaginationBoundary(): void + { + $fixture = $this->loadFixture('list_webhook_endpoint_json'); + // Ensure cursors are null (first/last page boundary) + $fixture['list_metadata']['before'] = null; + $fixture['list_metadata']['after'] = null; + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->webhooks()->listWebhookEndpoints(); + $this->assertInstanceOf(\WorkOS\PaginatedResponse::class, $result); + // Verify cursors are null on boundary page + $this->assertNull($result->listMetadata['before']); + $this->assertNull($result->listMetadata['after']); + // Iterating should not throw on null cursors + foreach ($result as $item) { + $this->assertNotNull($item); + break; + } + } +} diff --git a/tests/Service/WidgetsTest.php b/tests/Service/WidgetsTest.php new file mode 100644 index 00000000..ce415368 --- /dev/null +++ b/tests/Service/WidgetsTest.php @@ -0,0 +1,30 @@ +loadFixture('widget_session_token_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->widgets()->createToken(organizationId: 'test_value'); + $this->assertInstanceOf(\WorkOS\Resource\WidgetSessionTokenResponse::class, $result); + $this->assertSame($fixture['token'], $result->token); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('widgets/token', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test_value', $body['organization_id']); + } +} diff --git a/tests/SessionManagerTest.php b/tests/SessionManagerTest.php new file mode 100644 index 00000000..713f0238 --- /dev/null +++ b/tests/SessionManagerTest.php @@ -0,0 +1,140 @@ +cookiePassword = base64_encode(random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES)); + } + + // -- H06: seal/unseal -- + + public function testSealAndUnsealData(): void + { + $data = ['access_token' => 'tok_123', 'refresh_token' => 'ref_456']; + $sealed = SessionManager::sealData($data, $this->cookiePassword); + $this->assertIsString($sealed); + $this->assertNotSame(json_encode($data), $sealed); + + $unsealed = SessionManager::unsealData($sealed, $this->cookiePassword); + $this->assertSame($data, $unsealed); + } + + public function testUnsealWithWrongKey(): void + { + $data = ['access_token' => 'tok_123']; + $sealed = SessionManager::sealData($data, $this->cookiePassword); + + $wrongKey = base64_encode(random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES)); + $this->expectException(\InvalidArgumentException::class); + SessionManager::unsealData($sealed, $wrongKey); + } + + // -- H07: Auth response sealing -- + + public function testSealSessionFromAuthResponse(): void + { + $sealed = SessionManager::sealSessionFromAuthResponse( + accessToken: 'access_tok_123', + refreshToken: 'refresh_tok_456', + cookiePassword: $this->cookiePassword, + user: ['id' => 'usr_123', 'email' => 'test@example.com'], + ); + + $this->assertIsString($sealed); + + $unsealed = SessionManager::unsealData($sealed, $this->cookiePassword); + $this->assertSame('access_tok_123', $unsealed['access_token']); + $this->assertSame('refresh_tok_456', $unsealed['refresh_token']); + $this->assertSame('usr_123', $unsealed['user']['id']); + } + + // -- H04: Session cookie authenticate -- + + public function testAuthenticateNoSession(): void + { + $client = $this->createMockClient([]); + $result = $client->sessionManager()->authenticate( + sessionData: '', + cookiePassword: $this->cookiePassword, + clientId: 'client_123', + ); + $this->assertFalse($result['authenticated']); + $this->assertSame('no_session_cookie_provided', $result['reason']); + } + + public function testAuthenticateInvalidCookie(): void + { + $client = $this->createMockClient([]); + $result = $client->sessionManager()->authenticate( + sessionData: 'not-a-valid-sealed-string', + cookiePassword: $this->cookiePassword, + clientId: 'client_123', + ); + $this->assertFalse($result['authenticated']); + $this->assertSame('invalid_session_cookie', $result['reason']); + } + + public function testAuthenticateMissingAccessToken(): void + { + $sealed = SessionManager::sealData( + ['refresh_token' => 'ref_123'], + $this->cookiePassword, + ); + + $client = $this->createMockClient([]); + $result = $client->sessionManager()->authenticate( + sessionData: $sealed, + cookiePassword: $this->cookiePassword, + clientId: 'client_123', + ); + $this->assertFalse($result['authenticated']); + $this->assertSame('invalid_session_cookie', $result['reason']); + } + + // -- H13: JWKS helper -- + + public function testGetJwksUrl(): void + { + $url = SessionManager::getJwksUrl('client_123'); + $this->assertSame('https://api.workos.com/sso/jwks/client_123', $url); + } + + public function testGetJwksUrlCustomBase(): void + { + $url = SessionManager::getJwksUrl('client_123', 'https://custom.workos.com/'); + $this->assertSame('https://custom.workos.com/sso/jwks/client_123', $url); + } + + public function testFetchJwks(): void + { + $fixture = ['keys' => [['kty' => 'RSA', 'kid' => 'key_1']]]; + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->sessionManager()->fetchJwks('client_123'); + $this->assertArrayHasKey('keys', $result); + $request = $this->getLastRequest(); + $this->assertStringEndsWith('sso/jwks/client_123', $request->getUri()->getPath()); + } + + public function testSessionManagerAccessibleFromClient(): void + { + $client = $this->createMockClient([]); + $this->assertInstanceOf(SessionManager::class, $client->sessionManager()); + } +} diff --git a/tests/TestHelper.php b/tests/TestHelper.php index 2db39c24..7b5a7240 100644 --- a/tests/TestHelper.php +++ b/tests/TestHelper.php @@ -1,109 +1,66 @@ defaultRequestClient = Client::requestClient(); - $this->requestClientMock = $this->createMock("\WorkOS\RequestClient\RequestClientInterface"); + $path = __DIR__ . '/Fixtures/' . $name . '.json'; + if (!file_exists($path)) { + $this->markTestSkipped("Fixture not found: {$name}.json"); + } + return json_decode(file_get_contents($path), true); } - protected function tearDown(): void - { - WorkOS::setApiKey(null); - WorkOS::setClientId(null); - - Client::setRequestClient($this->defaultRequestClient); + protected function createMockClient( + array $responses, + string $apiKey = 'test_api_key', + ?string $clientId = 'test_client_id', + string $baseUrl = 'https://api.workos.com', + int $maxRetries = 3, + ): WorkOS { + $mockResponses = array_map( + fn (array $response) => new Response( + $response['status'] ?? 200, + $response['headers'] ?? [], + json_encode($response['body'] ?? []) + ), + $responses, + ); + + $this->mockHandler = new MockHandler($mockResponses); + $handler = HandlerStack::create($this->mockHandler); + $this->requestHistory = []; + $handler->push(Middleware::history($this->requestHistory)); + + return new WorkOS( + apiKey: $apiKey, + clientId: $clientId, + baseUrl: $baseUrl, + maxRetries: $maxRetries, + handler: $handler, + ); } - // Configuration - - protected function withApiKey($apiKey = "pk_secretsauce") + protected function getLastRequest(): \Psr\Http\Message\RequestInterface { - WorkOS::setApiKey($apiKey); - } - - protected function withApiKeyAndClientId($apiKey = "pk_secretsauce", $clientId = "client_pizza") - { - WorkOS::setApiKey($apiKey); - WorkOS::setClientId($clientId); - } - - // Requests - - protected function mockRequest( - $method, - $path, - $headers = null, - $params = null, - $withAuth = false, - $result = null, - $responseHeaders = null, - $responseCode = 200 - ) { - Client::setRequestClient($this->requestClientMock); - - $url = Client::generateUrl($path); - if (!$headers) { - $requestHeaders = Client::generateBaseHeaders($withAuth); - } else { - $requestHeaders = \array_merge(Client::generateBaseHeaders($withAuth), $headers); - } - - if (!$result) { - $result = "{}"; - } - if (!$responseHeaders) { - $responseHeaders = []; - } - - $this->prepareRequestMock($method, $url, $requestHeaders, $params) - ->willReturn([$result, $responseHeaders, $responseCode]); - } - - protected function secondMockRequest( - $method, - $path, - $headers = null, - $params = null, - $withAuth = false, - $result = null, - $responseHeaders = null, - $responseCode = 200 - ) { - Client::setRequestClient($this->requestClientMock); - $url = Client::generateUrl($path); - if (!$headers) { - $requestHeaders = Client::generateBaseHeaders($withAuth); - } else { - $requestHeaders = \array_merge(Client::generateBaseHeaders(), $headers); - } - - if (!$result) { - $result = "{}"; - } - if (!$responseHeaders) { - $responseHeaders = []; - } - - $this->prepareRequestMock($method, $url, $requestHeaders, $params) - ->willReturn([$result, $responseHeaders, $responseCode]); + return $this->requestHistory[array_key_last($this->requestHistory)]['request']; } - private function prepareRequestMock($method, $url, $headers, $params) + protected function getLastRequestOptions(): array { - return $this->requestClientMock - ->expects(static::atLeastOnce())->method('request') - ->with( - static::identicalTo($method), - static::identicalTo($url), - static::identicalTo($headers), - static::identicalTo($params) - ); + return $this->requestHistory[array_key_last($this->requestHistory)]['options']; } } diff --git a/tests/VaultTest.php b/tests/VaultTest.php new file mode 100644 index 00000000..3d698a0f --- /dev/null +++ b/tests/VaultTest.php @@ -0,0 +1,123 @@ + 'obj_1', 'name' => 'test', 'value' => 'secret']; + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->vault()->readObject('obj_1'); + $this->assertSame('obj_1', $result['id']); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('vault/v1/kv/obj_1', $request->getUri()->getPath()); + } + + public function testReadObjectByName(): void + { + $fixture = ['id' => 'obj_1', 'name' => 'my-secret']; + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->vault()->readObjectByName('my-secret'); + $this->assertSame('my-secret', $result['name']); + $request = $this->getLastRequest(); + $this->assertStringEndsWith('vault/v1/kv/name/my-secret', $request->getUri()->getPath()); + } + + public function testGetObjectMetadata(): void + { + $fixture = ['id' => 'obj_1', 'metadata' => []]; + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $client->vault()->getObjectMetadata('obj_1'); + $request = $this->getLastRequest(); + $this->assertStringEndsWith('vault/v1/kv/obj_1/metadata', $request->getUri()->getPath()); + } + + public function testListObjects(): void + { + $fixture = ['data' => [], 'list_metadata' => []]; + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $client->vault()->listObjects(); + $request = $this->getLastRequest(); + $this->assertSame('GET', $request->getMethod()); + $this->assertStringEndsWith('vault/v1/kv', $request->getUri()->getPath()); + } + + public function testListObjectVersions(): void + { + $fixture = ['data' => []]; + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $client->vault()->listObjectVersions('obj_1'); + $request = $this->getLastRequest(); + $this->assertStringEndsWith('vault/v1/kv/obj_1/versions', $request->getUri()->getPath()); + } + + public function testCreateObject(): void + { + $fixture = ['id' => 'obj_1', 'name' => 'test']; + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $client->vault()->createObject('test', 'secret_value', ['env' => 'production']); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('vault/v1/kv', $request->getUri()->getPath()); + $body = json_decode((string) $request->getBody(), true); + $this->assertSame('test', $body['name']); + $this->assertSame('secret_value', $body['value']); + } + + public function testUpdateObject(): void + { + $fixture = ['id' => 'obj_1', 'value' => 'new_value']; + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $client->vault()->updateObject('obj_1', 'new_value'); + $request = $this->getLastRequest(); + $this->assertSame('PUT', $request->getMethod()); + $this->assertStringEndsWith('vault/v1/kv/obj_1', $request->getUri()->getPath()); + } + + public function testDeleteObject(): void + { + $client = $this->createMockClient([['status' => 204]]); + $client->vault()->deleteObject('obj_1'); + $request = $this->getLastRequest(); + $this->assertSame('DELETE', $request->getMethod()); + $this->assertStringEndsWith('vault/v1/kv/obj_1', $request->getUri()->getPath()); + } + + public function testCreateDataKey(): void + { + $fixture = ['id' => 'key_1', 'data_key' => 'base64key', 'context' => [], 'encrypted_keys' => 'enc']; + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $client->vault()->createDataKey(['env' => 'prod']); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('vault/v1/keys/data-key', $request->getUri()->getPath()); + } + + public function testDecryptDataKey(): void + { + $fixture = ['id' => 'key_1', 'data_key' => 'decrypted_key']; + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $client->vault()->decryptDataKey('encrypted_keys_value'); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('vault/v1/keys/decrypt', $request->getUri()->getPath()); + } + + public function testVaultAccessibleFromClient(): void + { + $client = $this->createMockClient([]); + $this->assertInstanceOf(Vault::class, $client->vault()); + } +} diff --git a/tests/WebhookVerificationTest.php b/tests/WebhookVerificationTest.php new file mode 100644 index 00000000..6bac53a9 --- /dev/null +++ b/tests/WebhookVerificationTest.php @@ -0,0 +1,89 @@ + 'user.created', 'data' => ['id' => '123']]); + $timestamp = (string) (time() * 1000); // milliseconds + $expectedSig = hash_hmac('sha256', "{$timestamp}.{$payload}", self::SECRET); + $sigHeader = "t={$timestamp}, v1={$expectedSig}"; + + $client = $this->createMockClient([]); + $result = $client->webhookVerification()->verifyEvent( + eventBody: $payload, + eventSignature: $sigHeader, + secret: self::SECRET, + ); + $this->assertSame('user.created', $result['event']); + $this->assertSame('123', $result['data']['id']); + } + + public function testVerifyEventInvalidSignature(): void + { + $payload = '{"event":"test"}'; + $timestamp = (string) (time() * 1000); + $sigHeader = "t={$timestamp}, v1=invalidsignature"; + + $client = $this->createMockClient([]); + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Signature hash does not match'); + $client->webhookVerification()->verifyEvent( + eventBody: $payload, + eventSignature: $sigHeader, + secret: self::SECRET, + ); + } + + public function testVerifyEventExpiredTimestamp(): void + { + $payload = '{"event":"test"}'; + $timestamp = (string) ((time() - 300) * 1000); // 5 minutes ago + $expectedSig = hash_hmac('sha256', "{$timestamp}.{$payload}", self::SECRET); + $sigHeader = "t={$timestamp}, v1={$expectedSig}"; + + $client = $this->createMockClient([]); + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Timestamp outside the tolerance zone'); + $client->webhookVerification()->verifyEvent( + eventBody: $payload, + eventSignature: $sigHeader, + secret: self::SECRET, + ); + } + + public function testGetTimestampAndSignatureHash(): void + { + $sigHeader = 't=1234567890, v1=abcdef1234567890'; + [$timestamp, $hash] = WebhookVerification::getTimestampAndSignatureHash($sigHeader); + $this->assertSame('1234567890', $timestamp); + $this->assertSame('abcdef1234567890', $hash); + } + + public function testComputeSignature(): void + { + $expected = hash_hmac('sha256', '12345.payload', 'secret'); + $result = WebhookVerification::computeSignature('12345', 'payload', 'secret'); + $this->assertSame($expected, $result); + } + + public function testWebhookVerificationAccessibleFromClient(): void + { + $client = $this->createMockClient([]); + $this->assertInstanceOf(WebhookVerification::class, $client->webhookVerification()); + } +} diff --git a/tests/WorkOS/AuditLogsTest.php b/tests/WorkOS/AuditLogsTest.php deleted file mode 100644 index 41b16b3f..00000000 --- a/tests/WorkOS/AuditLogsTest.php +++ /dev/null @@ -1,469 +0,0 @@ -traitSetUp(); - - $this->withApiKeyAndClientId(); - $this->al = new AuditLogs(); - } - - public function testCreateEvent() - { - $path = "audit_logs/events"; - - $idempotencyKey = null; - $organizationId = "org_123"; - $auditLogEvent = - [ - "action" => "document.updated", - "occurred_at" => time(), - "version" => 1, - "actor" => - [ - "Id" => "user_123", - "Type" => "user", - "Name" => "User", - ], - "targets" => - [ - "id" => "team_123", - "type" => "team", - "name" => "team", - ]]; - $params = [ - "organization_id" => $organizationId, - "event" => $auditLogEvent - ]; - - $headers = [ - "idempotency_key" => $idempotencyKey - ]; - - $result = $this->createEventResponseFixture(); - - $this->mockRequest( - Client::METHOD_POST, - $path, - $headers, - $params, - true, - $result - ); - - $eventStatus = $this->al->createEvent($organizationId, $auditLogEvent); - $eventFixture = $this->createEventFixture(); - - $this->assertSame($eventFixture, $eventStatus->toArray()); - } - - public function testCreateExport() - { - $path = "audit_logs/exports"; - - $organizationId = "org_123"; - $rangeStart = "2022-08-18T18:07:10.822Z"; - $rangeEnd = "2022-08-18T18:07:10.822Z"; - $targets = [ - "id" => "team_123", - "type" => "team", - "name" => "team", - ]; - $actions = ["document.updated"]; - $actors = ["Smith"]; - $actorNames = ["Smith"]; - $actorIds = ["user_123"]; - $params = [ - "organization_id" => $organizationId, - "range_end" => $rangeEnd, - "range_start" => $rangeStart, - "actions" => $actions, - "actors" => $actors, - "actor_names" => $actorNames, - "actor_ids" => $actorIds, - "targets" => $targets - ]; - - $result = $this->createExportResponseFixture(); - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $auditLogExport = $this->al->createExport($organizationId, $rangeStart, $rangeEnd, $actions, $actors, $targets, $actorNames, $actorIds); - $exportFixture = $this->createExportFixture(); - - $this->assertSame($exportFixture, $auditLogExport->toArray()); - } - - public function testCreateExportWithNullOptionalParams() - { - $path = "audit_logs/exports"; - - $organizationId = "org_123"; - $rangeStart = "2022-08-18T18:07:10.822Z"; - $rangeEnd = "2022-08-18T18:07:10.822Z"; - // The implementation filters out null values, so they won't be in the params array - $params = [ - "organization_id" => $organizationId, - "range_end" => $rangeEnd, - "range_start" => $rangeStart - ]; - - $result = $this->createExportResponseFixture(); - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $auditLogExport = $this->al->createExport($organizationId, $rangeStart, $rangeEnd, null, null, null, null, null); - $exportFixture = $this->createExportFixture(); - - $this->assertSame($exportFixture, $auditLogExport->toArray()); - } - - public function testGetExport() - { - $auditLogExportId = "123"; - - $path = "audit_logs/exports/{$auditLogExportId}"; - - $result = $this->getExportResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - null, - true, - $result - ); - - $auditLogGetExport = $this->al->getExport($auditLogExportId); - $getExportFixture = $this->getExportFixture(); - - $this->assertSame($getExportFixture, $auditLogGetExport->toArray()); - } - - public function testCreateSchema() - { - $path = "audit_logs/actions/document.updated/schemas"; - - $action = "document.updated"; - $schema = [ - "targets" => [ - [ - "type" => "document" - ], - [ - "type" => "user" - ] - ] - ]; - - $params = $schema; - - $result = $this->createSchemaResponseFixture(); - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $response = $this->al->createSchema($action, $schema); - $schemaFixture = $this->createSchemaFixture(); - - $this->assertSame($schemaFixture, $response); - } - - public function testSchemaExists() - { - $path = "audit_logs/actions/document.updated/schemas"; - $action = "document.updated"; - - $result = $this->schemaExistsResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - null, - true, - $result - ); - - $exists = $this->al->schemaExists($action); - - $this->assertTrue($exists); - } - - public function testSchemaExistsNotFound() - { - $path = "audit_logs/actions/nonexistent.action/schemas"; - $action = "nonexistent.action"; - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - null, - true, - null, - null, - 404 - ); - - $exists = $this->al->schemaExists($action); - - $this->assertFalse($exists); - } - - public function testListActions() - { - $path = "audit_logs/actions"; - - $params = [ - "limit" => 100 - ]; - - $result = $this->listActionsResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - $params, - true, - $result - ); - - $response = $this->al->listActions(); - $actionsFixture = $this->listActionsFixture(); - - $this->assertSame($actionsFixture, $response); - } - - public function testListActionsWithPagination() - { - $path = "audit_logs/actions"; - - $params = [ - "limit" => 50, - "before" => "action_123", - "after" => "action_456", - "order" => "desc" - ]; - - $result = $this->listActionsResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - $params, - true, - $result - ); - - $response = $this->al->listActions(50, "action_123", "action_456", "desc"); - $actionsFixture = $this->listActionsFixture(); - - $this->assertSame($actionsFixture, $response); - } - // Fixtures - - private function createEventFixture() - { - return [ - "success" => true - ]; - } - - private function createEventResponseFixture() - { - return json_encode([ - "success" => true - ]); - } - - private function createExportFixture() - { - return [ - "object" => "audit_log_export", - "id" => "audit_log_export_123", - "state" => "ready", - "url" => "https://audit-logs.com/download.csv", - "createdAt" => "2022-08-18T18:07:10.822Z", - "updatedAt" => "2022-08-18T18:07:10.822Z", - ]; - } - - private function createExportResponseFixture() - { - return json_encode([ - "object" => "audit_log_export", - "id" => "audit_log_export_123", - "state" => "ready", - "url" => "https://audit-logs.com/download.csv", - "created_at" => "2022-08-18T18:07:10.822Z", - "updated_at" => "2022-08-18T18:07:10.822Z", - ]); - } - - private function getExportFixture() - { - return [ - "object" => "audit_log_export", - "id" => "audit_log_export_123", - "state" => "ready", - "url" => "https://audit-logs.com/download.csv", - "createdAt" => "2022-08-18T18:07:10.822Z", - "updatedAt" => "2022-08-18T18:07:10.822Z", - ]; - } - - private function getExportResponseFixture() - { - return json_encode([ - "object" => "audit_log_export", - "id" => "audit_log_export_123", - "state" => "ready", - "url" => "https://audit-logs.com/download.csv", - "created_at" => "2022-08-18T18:07:10.822Z", - "updated_at" => "2022-08-18T18:07:10.822Z", - ]); - } - - private function createSchemaFixture() - { - return [ - "object" => "audit_log_schema", - "id" => "schema_123", - "action" => "document.updated", - "targets" => [ - ["type" => "document"], - ["type" => "user"] - ], - "created_at" => "2022-08-18T18:07:10.822Z", - "updated_at" => "2022-08-18T18:07:10.822Z", - ]; - } - - private function createSchemaResponseFixture() - { - return json_encode([ - "object" => "audit_log_schema", - "id" => "schema_123", - "action" => "document.updated", - "targets" => [ - ["type" => "document"], - ["type" => "user"] - ], - "created_at" => "2022-08-18T18:07:10.822Z", - "updated_at" => "2022-08-18T18:07:10.822Z", - ]); - } - - private function schemaExistsResponseFixture() - { - return json_encode([ - "object" => "audit_log_schema", - "id" => "schema_123", - "action" => "document.updated", - "targets" => [ - ["type" => "document"] - ], - "created_at" => "2022-08-18T18:07:10.822Z", - "updated_at" => "2022-08-18T18:07:10.822Z", - ]); - } - - private function listActionsFixture() - { - return [ - "object" => "list", - "data" => [ - [ - "object" => "audit_log_action", - "id" => "action_123", - "name" => "document.updated", - "description" => "Document was updated", - "created_at" => "2022-08-18T18:07:10.822Z", - "updated_at" => "2022-08-18T18:07:10.822Z", - ], - [ - "object" => "audit_log_action", - "id" => "action_456", - "name" => "user.created", - "description" => "User was created", - "created_at" => "2022-08-18T18:07:10.822Z", - "updated_at" => "2022-08-18T18:07:10.822Z", - ] - ], - "list_metadata" => [ - "before" => null, - "after" => "action_456", - "limit" => 100 - ] - ]; - } - - private function listActionsResponseFixture() - { - return json_encode([ - "object" => "list", - "data" => [ - [ - "object" => "audit_log_action", - "id" => "action_123", - "name" => "document.updated", - "description" => "Document was updated", - "created_at" => "2022-08-18T18:07:10.822Z", - "updated_at" => "2022-08-18T18:07:10.822Z", - ], - [ - "object" => "audit_log_action", - "id" => "action_456", - "name" => "user.created", - "description" => "User was created", - "created_at" => "2022-08-18T18:07:10.822Z", - "updated_at" => "2022-08-18T18:07:10.822Z", - ] - ], - "list_metadata" => [ - "before" => null, - "after" => "action_456", - "limit" => 100 - ] - ]); - } -} diff --git a/tests/WorkOS/ClientTest.php b/tests/WorkOS/ClientTest.php deleted file mode 100644 index 654ce9be..00000000 --- a/tests/WorkOS/ClientTest.php +++ /dev/null @@ -1,264 +0,0 @@ -withApiKeyAndClientId(); - - $path = "some/place"; - - $this->expectException($exceptionClass); - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - null, - false, - null, - null, - $statusCode - ); - - Client::request(Client::METHOD_GET, $path); - } - - /** - * @dataProvider requestExceptionTestProvider - */ - public function testClientThrowsRequestExceptionsIncludeRequestId($statusCode, $exceptionClass) - { - $this->withApiKeyAndClientId(); - - $path = "some/place"; - $responseHeaders = ["x-request-id" => "123yocheckme"]; - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - null, - false, - null, - $responseHeaders, - $statusCode - ); - - try { - Client::request(Client::METHOD_GET, $path); - } catch (Exception\BaseRequestException $e) { - $this->assertEquals($e->requestId, $responseHeaders["x-request-id"]); - return; - } - - $this->fail("Expected exception of type " . $exceptionClass . " not thrown."); - } - - /** - * @dataProvider requestExceptionTestProvider - */ - public function testClientThrowsRequestExceptionsWithBadMessage($statusCode, $exceptionClass) - { - $this->withApiKeyAndClientId(); - - $path = "some/place"; - $result = "thisaintjson"; - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - null, - false, - $result, - null, - $statusCode - ); - - try { - Client::request(Client::METHOD_GET, $path); - } catch (Exception\BaseRequestException $e) { - $this->assertEquals($e->getMessage(), $result); - $this->assertEquals($e->response->json(), json_decode($result, true)); - } - } - - /** - * @dataProvider requestExceptionTestProvider - */ - public function testClientThrowsRequestExceptionsWithMessageAndCode($statusCode, $exceptionClass) - { - $this->withApiKeyAndClientId(); - - $path = "some/place"; - $result = $this->messageAndCodeFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - null, - false, - $result, - null, - $statusCode - ); - - try { - Client::request(Client::METHOD_GET, $path); - } catch (Exception\BaseRequestException $e) { - // var_dump($e); - $this->assertEquals($e->responseMessage, "Start date cannot be before 2022-06-22T00:00:00.000Z."); - $this->assertEquals($e->responseCode, "invalid_date_range_exception"); - $this->assertEquals($e->response->json(), json_decode($result, true)); - } - } - - /** - * @dataProvider requestExceptionTestProvider - */ - public function testClientThrowsRequestExceptionsWithErrorAndErrorDescription($statusCode, $exceptionClass) - { - $this->withApiKeyAndClientId(); - - $path = "some/place"; - $result = $this->errorAndErrorDescriptionFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - null, - false, - $result, - null, - $statusCode - ); - - try { - Client::request(Client::METHOD_GET, $path); - } catch (Exception\BaseRequestException $e) { - // var_dump($e); - $this->assertEquals($e->responseError, "invalid_grant"); - $this->assertEquals($e->responseErrorDescription, "The code '01GDK892VGKGVF2QNWVTABG8MX' has expired or is invalid."); - $this->assertEquals($e->response->json(), json_decode($result, true)); - } - } - - /** - * @dataProvider requestExceptionTestProvider - */ - public function testClientThrowsRequestExceptionsWithErrors($statusCode, $exceptionClass) - { - $this->withApiKeyAndClientId(); - - $path = "some/place"; - $result = $this->errorsArrayFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - null, - false, - $result, - null, - $statusCode - ); - - try { - Client::request(Client::METHOD_GET, $path); - } catch (Exception\BaseRequestException $e) { - // var_dump($e); - $this->assertEquals($e->responseErrors, ["invalid_grant", "ambiguous_connection_selector"]); - $this->assertEquals($e->response->json(), json_decode($result, true)); - } - } - - public function testClientRequestWithNullHeadersAndParams() - { - $this->withApiKeyAndClientId(); - - $path = "some/place"; - $result = json_encode(["data" => "test"]); - - // Client::request always generates base headers even when null is passed - // When $withAuth is false (default), it still includes User-Agent header - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - null, - false, - $result - ); - - $response = Client::request(Client::METHOD_GET, $path, null, null); - $this->assertSame(["data" => "test"], $response); - } - - public function testClientGenerateUrl() - { - $this->withApiKeyAndClientId(); - - $path = "test/path"; - $url = Client::generateUrl($path); - $this->assertStringContainsString($path, $url); - } - - public function testClientGenerateUrlWithNullParams() - { - $this->withApiKeyAndClientId(); - - $path = "test/path"; - $url = Client::generateUrl($path, null); - $this->assertStringContainsString($path, $url); - } - - // Providers - public static function requestExceptionTestProvider() - { - return [ - [400, Exception\BadRequestException::class], - [401, Exception\AuthenticationException::class], - [403, Exception\AuthorizationException::class], - [404, Exception\NotFoundException::class], - [500, Exception\ServerException::class], - [503, Exception\ServerException::class], - [504, Exception\ServerException::class] - ]; - } - - private function messageAndCodeFixture() - { - return json_encode([ - "message" => "Start date cannot be before 2022-06-22T00:00:00.000Z.", - "code" => "invalid_date_range_exception" - ]); - } - - private function errorAndErrorDescriptionFixture() - { - return json_encode([ - "error" => "invalid_grant", - "error_description" => "The code '01GDK892VGKGVF2QNWVTABG8MX' has expired or is invalid." - ]); - } - - private function errorsArrayFixture() - { - return json_encode([ - "errors" => ["invalid_grant", "ambiguous_connection_selector"] - ]); - } -} diff --git a/tests/WorkOS/CookieSessionTest.php b/tests/WorkOS/CookieSessionTest.php deleted file mode 100644 index 1398c3c8..00000000 --- a/tests/WorkOS/CookieSessionTest.php +++ /dev/null @@ -1,252 +0,0 @@ -traitSetUp(); - $this->withApiKeyAndClientId(); - $this->userManagement = new UserManagement(); - - // Create a sealed session for testing using encryptor directly - // (sealing is authkit-php's responsibility, not SDK's) - $sessionData = [ - 'access_token' => 'test_access_token_12345', - 'refresh_token' => 'test_refresh_token_67890', - 'session_id' => 'session_01H7X1M4TZJN5N4HG4XXMA1234' - ]; - $encryptor = new Session\HaliteSessionEncryption(); - $this->sealedSession = $encryptor->seal($sessionData, $this->cookiePassword); - } - - public function testConstructCookieSession() - { - $cookieSession = new CookieSession( - $this->userManagement, - $this->sealedSession, - $this->cookiePassword - ); - - $this->assertInstanceOf(CookieSession::class, $cookieSession); - } - - public function testAuthenticateFailsWithInvalidSession() - { - $cookieSession = new CookieSession( - $this->userManagement, - "invalid-sealed-session-data", - $this->cookiePassword - ); - - $result = $cookieSession->authenticate(); - - $this->assertInstanceOf( - Resource\SessionAuthenticationFailureResponse::class, - $result - ); - $this->assertFalse($result->authenticated); - } - - public function testGetLogoutUrlThrowsExceptionForUnauthenticatedSession() - { - $cookieSession = new CookieSession( - $this->userManagement, - "invalid-sealed-session-data", - $this->cookiePassword - ); - - $this->expectException(Exception\UnexpectedValueException::class); - $this->expectExceptionMessage("Cannot get logout URL for unauthenticated session"); - - $cookieSession->getLogoutUrl(); - } - - public function testLoadSealedSessionReturnsValidCookieSession() - { - $cookieSession = $this->userManagement->loadSealedSession( - $this->sealedSession, - $this->cookiePassword - ); - - $this->assertInstanceOf(CookieSession::class, $cookieSession); - } - - public function testRefreshReturnsRawTokensOnSuccess() - { - $organizationId = "org_01H7X1M4TZJN5N4HG4XXMA1234"; - - // Create a mock UserManagement to verify method calls - $userManagementMock = $this->getMockBuilder(UserManagement::class) - ->onlyMethods(['authenticateWithSessionCookie', 'authenticateWithRefreshToken']) - ->getMock(); - - // Mock authenticateWithSessionCookie to return a successful authentication - $authResponseData = [ - 'authenticated' => true, - 'access_token' => 'test_access_token', - 'refresh_token' => 'test_refresh_token', - 'session_id' => 'session_123', - 'user' => [ - 'object' => 'user', - 'id' => 'user_123', - 'email' => 'test@test.com', - 'first_name' => 'Test', - 'last_name' => 'User', - 'email_verified' => true, - 'created_at' => '2021-01-01T00:00:00.000Z', - 'updated_at' => '2021-01-01T00:00:00.000Z' - ] - ]; - $authResponse = Resource\SessionAuthenticationSuccessResponse::constructFromResponse($authResponseData); - $userManagementMock->method('authenticateWithSessionCookie') - ->willReturn($authResponse); - - // Setup refresh to succeed - $refreshResponseData = [ - 'access_token' => 'new_access_token', - 'refresh_token' => 'new_refresh_token', - 'user' => [ - 'object' => 'user', - 'id' => 'user_123', - 'email' => 'test@test.com', - 'first_name' => 'Test', - 'last_name' => 'User', - 'email_verified' => true, - 'created_at' => '2021-01-01T00:00:00.000Z', - 'updated_at' => '2021-01-01T00:00:00.000Z' - ] - ]; - $refreshResponse = Resource\AuthenticationResponse::constructFromResponse($refreshResponseData); - - $userManagementMock->expects($this->once()) - ->method('authenticateWithRefreshToken') - ->with( - $this->identicalTo(WorkOS::getClientId()), // clientId from config - $this->identicalTo('test_refresh_token'), // refresh token - $this->identicalTo(null), // ipAddress - $this->identicalTo(null), // userAgent - $this->identicalTo($organizationId) // organizationId - ) - ->willReturn($refreshResponse); - - // Execute refresh with the mocked UserManagement - $cookieSession = new CookieSession( - $userManagementMock, - $this->sealedSession, - $this->cookiePassword - ); - - [$response, $tokens] = $cookieSession->refresh([ - 'organizationId' => $organizationId - ]); - - // Verify response is successful - $this->assertInstanceOf(Resource\SessionAuthenticationSuccessResponse::class, $response); - $this->assertTrue($response->authenticated); - - // Verify tokens are returned as raw array (not sealed) - $this->assertIsArray($tokens); - $this->assertArrayHasKey('access_token', $tokens); - $this->assertArrayHasKey('refresh_token', $tokens); - $this->assertArrayHasKey('session_id', $tokens); - $this->assertEquals('new_access_token', $tokens['access_token']); - $this->assertEquals('new_refresh_token', $tokens['refresh_token']); - $this->assertEquals('session_123', $tokens['session_id']); - } - - public function testRefreshReturnsNullTokensOnAuthFailure() - { - $userManagementMock = $this->getMockBuilder(UserManagement::class) - ->onlyMethods(['authenticateWithSessionCookie']) - ->getMock(); - - $failResponse = new Resource\SessionAuthenticationFailureResponse( - Resource\SessionAuthenticationFailureResponse::REASON_INVALID_SESSION_COOKIE - ); - - $userManagementMock->method('authenticateWithSessionCookie') - ->willReturn($failResponse); - - $cookieSession = new CookieSession( - $userManagementMock, - 'invalid-session', - $this->cookiePassword - ); - - [$response, $tokens] = $cookieSession->refresh(); - - $this->assertFalse($response->authenticated); - $this->assertNull($tokens); - } - - public function testRefreshReturnsHttpErrorOnApiFailure() - { - $userManagementMock = $this->getMockBuilder(UserManagement::class) - ->onlyMethods(['authenticateWithSessionCookie', 'authenticateWithRefreshToken']) - ->getMock(); - - // Mock successful initial auth - $authResponseData = [ - 'authenticated' => true, - 'access_token' => 'test_access_token', - 'refresh_token' => 'test_refresh_token', - 'session_id' => 'session_123', - 'user' => [ - 'object' => 'user', - 'id' => 'user_123', - 'email' => 'test@test.com', - 'first_name' => 'Test', - 'last_name' => 'User', - 'email_verified' => true, - 'created_at' => '2021-01-01T00:00:00.000Z', - 'updated_at' => '2021-01-01T00:00:00.000Z' - ] - ]; - $authResponse = Resource\SessionAuthenticationSuccessResponse::constructFromResponse($authResponseData); - $userManagementMock->method('authenticateWithSessionCookie') - ->willReturn($authResponse); - - // Mock refresh to throw HTTP exception - $response = new Resource\Response('{"error": "server_error"}', [], 500); - $userManagementMock->method('authenticateWithRefreshToken') - ->willThrowException(new Exception\ServerException($response)); - - $cookieSession = new CookieSession( - $userManagementMock, - $this->sealedSession, - $this->cookiePassword - ); - - [$response, $tokens] = $cookieSession->refresh(); - - $this->assertFalse($response->authenticated); - $this->assertEquals( - Resource\SessionAuthenticationFailureResponse::REASON_HTTP_ERROR, - $response->reason - ); - $this->assertNull($tokens); - } -} diff --git a/tests/WorkOS/DirectorySyncTest.php b/tests/WorkOS/DirectorySyncTest.php deleted file mode 100644 index 09c140fc..00000000 --- a/tests/WorkOS/DirectorySyncTest.php +++ /dev/null @@ -1,794 +0,0 @@ -traitSetUp(); - - $this->withApiKeyAndClientId(); - $this->ds = new DirectorySync(); - } - - public function testListDirectories() - { - $directoriesPath = "directories"; - $params = [ - "limit" => DirectorySync::DEFAULT_PAGE_SIZE, - "before" => null, - "after" => null, - "domain" => null, - "search" => null, - "organization_id" => null, - "order" => null - ]; - - $result = $this->directoriesResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $directoriesPath, - null, - $params, - true, - $result - ); - - $directory = $this->directoryFixture(); - - list($before, $after, $directories) = $this->ds->listDirectories(); - $this->assertSame($directory, $directories[0]->toArray()); - } - - public function testListDirectoriesPaginatedResourceAccessPatterns() - { - $directoriesPath = "directories"; - $params = [ - "limit" => DirectorySync::DEFAULT_PAGE_SIZE, - "before" => null, - "after" => null, - "domain" => null, - "search" => null, - "organization_id" => null, - "order" => null - ]; - - $result = $this->directoriesResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $directoriesPath, - null, - $params, - true, - $result - ); - - // Test 1: Bare destructuring (indexed) - [$before1, $after1, $directories1] = $this->ds->listDirectories(); - $this->assertNull($before1); - $this->assertNull($after1); - $this->assertIsArray($directories1); - $this->assertCount(1, $directories1); - - // Mock the request again for the next test - $this->mockRequest( - Client::METHOD_GET, - $directoriesPath, - null, - $params, - true, - $result - ); - - // Test 2: Named destructuring - ["before" => $before2, "after" => $after2, "directories" => $directories2] = $this->ds->listDirectories(); - $this->assertNull($before2); - $this->assertNull($after2); - $this->assertIsArray($directories2); - $this->assertCount(1, $directories2); - - // Mock the request again for the next test - $this->mockRequest( - Client::METHOD_GET, - $directoriesPath, - null, - $params, - true, - $result - ); - - // Test 3: Fluent access - $response = $this->ds->listDirectories(); - $this->assertNull($response->before); - $this->assertNull($response->after); - $this->assertIsArray($response->directories); - $this->assertCount(1, $response->directories); - - // Test 4: Generic data accessor - $this->assertIsArray($response->data); - $this->assertSame($response->directories, $response->data); - } - - public function testGetDirectory() - { - $directoryId = "directory_id"; - $directoryPath = "directories/{$directoryId}"; - - $result = $this->getDirectoryResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $directoryPath, - null, - null, - true, - $result - ); - - $directory = $this->ds->getDirectory($directoryId); - $directoryFixture = $this->getDirectoryFixture(); - - $this->assertSame($directoryFixture, $directory->toArray()); - } - - public function testGetGroup() - { - $directoryGroup = "directory_grp_id"; - $groupPath = "directory_groups/{$directoryGroup}"; - - $result = $this->groupResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $groupPath, - null, - null, - true, - $result - ); - - $group = $this->ds->getGroup($directoryGroup); - $groupFixture = $this->groupFixture(); - - $this->assertSame($groupFixture, $group->toArray()); - } - - public function testListGroups() - { - $usersPath = "directory_groups"; - $params = [ - "limit" => DirectorySync::DEFAULT_PAGE_SIZE, - "before" => null, - "after" => null, - "order" => null - ]; - - $result = $this->groupsResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $usersPath, - null, - $params, - true, - $result - ); - - $group = $this->groupFixture(); - - list($before, $after, $groups) = $this->ds->listGroups(); - $this->assertSame($group, $groups[0]->toArray()); - } - - public function testListGroupsPaginatedResourceAccessPatterns() - { - $usersPath = "directory_groups"; - $params = [ - "limit" => DirectorySync::DEFAULT_PAGE_SIZE, - "before" => null, - "after" => null, - "order" => null - ]; - - $result = $this->groupsResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $usersPath, - null, - $params, - true, - $result - ); - - // Test 1: Bare destructuring (indexed) - [$before1, $after1, $groups1] = $this->ds->listGroups(); - $this->assertNull($before1); - $this->assertNull($after1); - $this->assertIsArray($groups1); - $this->assertCount(1, $groups1); - - // Mock the request again for the next test - $this->mockRequest( - Client::METHOD_GET, - $usersPath, - null, - $params, - true, - $result - ); - - // Test 2: Named destructuring - ["before" => $before2, "after" => $after2, "groups" => $groups2] = $this->ds->listGroups(); - $this->assertNull($before2); - $this->assertNull($after2); - $this->assertIsArray($groups2); - $this->assertCount(1, $groups2); - - // Mock the request again for the next test - $this->mockRequest( - Client::METHOD_GET, - $usersPath, - null, - $params, - true, - $result - ); - - // Test 3: Fluent access - $response = $this->ds->listGroups(); - $this->assertNull($response->before); - $this->assertNull($response->after); - $this->assertIsArray($response->groups); - $this->assertCount(1, $response->groups); - - // Test 4: Generic data accessor - $this->assertIsArray($response->data); - $this->assertSame($response->groups, $response->data); - } - - public function testGetUser() - { - $directoryUser = "directory_usr_id"; - $userPath = "directory_users/{$directoryUser}"; - - $result = $this->userResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $userPath, - null, - null, - true, - $result - ); - - $user = $this->ds->getUser($directoryUser); - $userFixture = $this->userFixture(); - - $this->assertEquals($userFixture, $user->toArray()); - } - - public function testGetUserPrimaryEmail() - { - $directoryUser = "directory_usr_id"; - $userPath = "directory_users/{$directoryUser}"; - $expectedEmail = "yoon@seri.com"; - $result = $this->userResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $userPath, - null, - null, - true, - $result - ); - - $user = $this->ds->getUser($directoryUser); - $userEmail = $user->primaryEmail(); - - $this->assertSame($userEmail, $expectedEmail); - } - - public function testGetUserPrimaryEmailNoPrimaryEmail() - { - $directoryUser = "directory_usr_id"; - $userPath = "directory_users/{$directoryUser}"; - $expectedEmail = null; - $result = $this->userResponseFixtureNoEmail(); - - $this->mockRequest( - Client::METHOD_GET, - $userPath, - null, - null, - true, - $result - ); - - $user = $this->ds->getUser($directoryUser); - $userEmail = $user->primaryEmail(); - - $this->assertSame($userEmail, $expectedEmail); - } - - public function testListUsers() - { - $usersPath = "directory_users"; - $params = [ - "limit" => DirectorySync::DEFAULT_PAGE_SIZE, - "before" => null, - "after" => null, - "order" => null - ]; - - $result = $this->usersResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $usersPath, - null, - $params, - true, - $result - ); - - $user = $this->userFixture(); - - list($before, $after, $users) = $this->ds->listUsers(); - $this->assertEquals($user, $users[0]->toArray()); - } - - public function testListUsersPaginatedResourceAccessPatterns() - { - $usersPath = "directory_users"; - $params = [ - "limit" => DirectorySync::DEFAULT_PAGE_SIZE, - "before" => null, - "after" => null, - "order" => null - ]; - - $result = $this->usersResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $usersPath, - null, - $params, - true, - $result - ); - - // Test 1: Bare destructuring (indexed) - [$before1, $after1, $users1] = $this->ds->listUsers(); - $this->assertNull($before1); - $this->assertNull($after1); - $this->assertIsArray($users1); - $this->assertCount(1, $users1); - - // Mock the request again for the next test - $this->mockRequest( - Client::METHOD_GET, - $usersPath, - null, - $params, - true, - $result - ); - - // Test 2: Named destructuring - ["before" => $before2, "after" => $after2, "users" => $users2] = $this->ds->listUsers(); - $this->assertNull($before2); - $this->assertNull($after2); - $this->assertIsArray($users2); - $this->assertCount(1, $users2); - - // Mock the request again for the next test - $this->mockRequest( - Client::METHOD_GET, - $usersPath, - null, - $params, - true, - $result - ); - - // Test 3: Fluent access - $response = $this->ds->listUsers(); - $this->assertNull($response->before); - $this->assertNull($response->after); - $this->assertIsArray($response->users); - $this->assertCount(1, $response->users); - - // Test 4: Generic data accessor - $this->assertIsArray($response->data); - $this->assertSame($response->users, $response->data); - } - - public function testDeleteDirectory() - { - $directory = "directory_id"; - $directoryPath = "directories/{$directory}"; - $responseCode = 204; - - $this->mockRequest( - Client::METHOD_DELETE, - $directoryPath, - null, - null, - true, - null, - null, - $responseCode - ); - - $response = $this->ds->deleteDirectory($directory); - $this->assertSame(204, $responseCode); - } - - - // Fixtures - - private function directoriesResponseFixture() - { - return json_encode([ - "data" => [ - [ - "id" => "directory_id", - "external_key" => "fried-chicken", - "organization_id" => null, - "state" => "linked", - "type" => "gsuite directory", - "name" => "Ri Jeong Hyeok", - "bearer_token" => null, - "domain" => "crashlandingonyou.com", - ] - ], - "list_metadata" => [ - "before" => null, - "after" => null - ], - ]); - } - - private function directoryFixture() - { - return [ - "id" => "directory_id", - "externalKey" => "fried-chicken", - "organizationId" => null, - "state" => "linked", - "type" => "gsuite directory", - "name" => "Ri Jeong Hyeok", - "domain" => "crashlandingonyou.com" - ]; - } - - private function getDirectoryFixture() - { - return [ - "id" => "directory_id", - "externalKey" => "fried-chicken", - "organizationId" => null, - "state" => "linked", - "type" => "gsuite directory", - "name" => "Ri Jeong Hyeok", - "domain" => "crashlandingonyou.com" - ]; - } - - private function getDirectoryResponseFixture() - { - return json_encode([ - "id" => "directory_id", - "external_key" => "fried-chicken", - "organization_id" => null, - "state" => "linked", - "type" => "gsuite directory", - "name" => "Ri Jeong Hyeok", - "bearer_token" => null, - "domain" => "crashlandingonyou.com", - ]); - } - - private function groupsResponseFixture() - { - return json_encode([ - "data" => [ - [ - "name" => "Developers", - "id" => "directory_grp_id", - "directory_id" => "dir_123", - "organization_id" => "org_123" - ] - ], - "list_metadata" => [ - "before" => null, - "after" => null - ], - ]); - } - - private function groupResponseFixture() - { - return json_encode([ - "id" => "directory_grp_id", - "name" => "Developers", - "directory_id" => "dir_123", - "organization_id" => "org_123" - ]); - } - - private function groupFixture() - { - return [ - "id" => "directory_grp_id", - "name" => "Developers", - "directoryId" => "dir_123", - "organizationId" => "org_123" - ]; - } - - private function usersResponseFixture() - { - return json_encode([ - "list_metadata" => [ - "before" => null, - "after" => null - ], - "data" => [ - [ - "username" => "yoon@seri.com", - "state" => "active", - "last_name" => "Seri", - "first_name" => "Yoon", - "job_title" => "Software Engineer", - "directory_id" => "dir_123", - "organization_id" => "org_123", - "idp_id" => null, - "groups" => null, - "email" => "yoon@seri.com", - "emails" => [ - [ - "primary" => true, - "type" => "work", - "value" => "yoon@seri.com" - ] - ], - "raw_attributes" => [ - "schemas" => ["urn:scim:schemas:core:1.0"], - "name" => [ - "familyName" => "Seri", - "givenName" => "Yoon" - ], - "externalId" => "external-id", - "locale" => "en_US", - "userName" => "yoon@seri.com", - "title" => "Software Engineer", - "id" => "directory_usr_id", - "displayName" => "Yoon Seri", - "active" => true, - "groups" => [], - "meta" => [ - "created" => "2020-02-21T00:32:14.443Z", - "version" => "7ff066f75718e21a521c269ae7eafce474ae07c1", - "lastModified" => "2020-02-21T00:36:44.638Z", - ], - "emails" => [ - [ - "value" => "yoon@seri.com", - "type" => "work", - "primary" => true - ] - ], - ], - "custom_attributes" => [ - "fullName" => "Yoon Seri" - ], - "role" => [ - "slug" => "admin" - ], - "roles" => [ - [ - "slug" => "admin" - ] - ], - "id" => "directory_usr_id" - ] - ] - ]); - } - - private function userResponseFixture() - { - return json_encode([ - "username" => "yoon@seri.com", - "state" => "active", - "last_name" => "Seri", - "first_name" => "Yoon", - "job_title" => "Software Engineer", - "directory_id" => "dir_123", - "organization_id" => "org_123", - "idp_id" => null, - "groups" => null, - "email" => "yoon@seri.com", - "emails" => [ - [ - "primary" => true, - "type" => "work", - "value" => "yoon@seri.com" - ] - ], - "raw_attributes" => [ - "schemas" => ["urn:scim:schemas:core:1.0"], - "name" => [ - "familyName" => "Seri", - "givenName" => "Yoon" - ], - "externalId" => "external-id", - "locale" => "en_US", - "userName" => "yoon@seri.com", - "title" => "Software Engineer", - "id" => "directory_usr_id", - "displayName" => "Yoon Seri", - "active" => true, - "groups" => [], - "meta" => [ - "created" => "2020-02-21T00:32:14.443Z", - "version" => "7ff066f75718e21a521c269ae7eafce474ae07c1", - "lastModified" => "2020-02-21T00:36:44.638Z", - ], - "emails" => [ - [ - "value" => "yoon@seri.com", - "type" => "work", - "primary" => true - ] - ], - ], - "custom_attributes" => [ - "fullName" => "Yoon Seri" - ], - "role" => [ - "slug" => "admin" - ], - "roles" => [ - [ - "slug" => "admin" - ] - ], - "id" => "directory_usr_id" - ]); - } - - private function userResponseFixtureNoEmail() - { - return json_encode([ - "username" => "yoon@seri.com", - "state" => "active", - "last_name" => "Seri", - "first_name" => "Yoon", - "job_title" => "Software Engineer", - "directory_id" => "dir_123", - "organization_id" => "org_123", - "idp_id" => null, - "groups" => null, - "email" => null, - "emails" => [], - "raw_attributes" => [ - "schemas" => ["urn:scim:schemas:core:1.0"], - "name" => [ - "familyName" => "Seri", - "givenName" => "Yoon" - ], - "externalId" => "external-id", - "locale" => "en_US", - "userName" => "yoon@seri.com", - "title" => "Software Engineer", - "id" => "directory_usr_id", - "displayName" => "Yoon Seri", - "active" => true, - "groups" => [], - "meta" => [ - "created" => "2020-02-21T00:32:14.443Z", - "version" => "7ff066f75718e21a521c269ae7eafce474ae07c1", - "lastModified" => "2020-02-21T00:36:44.638Z", - ], - "emails" => [ - [ - "value" => "yoon@seri.com", - "type" => "work", - "primary" => true - ] - ], - ], - "custom_attributes" => [ - "fullName" => "Yoon Seri" - ], - "role" => [ - "slug" => "admin" - ], - "roles" => [ - [ - "slug" => "admin" - ] - ], - "id" => "directory_usr_id" - ]); - } - - private function userFixture() - { - return [ - "id" => "directory_usr_id", - "rawAttributes" => [ - "schemas" => ["urn:scim:schemas:core:1.0"], - "name" => [ - "familyName" => "Seri", - "givenName" => "Yoon" - ], - "externalId" => "external-id", - "locale" => "en_US", - "userName" => "yoon@seri.com", - "title" => "Software Engineer", - "id" => "directory_usr_id", - "displayName" => "Yoon Seri", - "active" => true, - "groups" => [], - "meta" => [ - "created" => "2020-02-21T00:32:14.443Z", - "version" => "7ff066f75718e21a521c269ae7eafce474ae07c1", - "lastModified" => "2020-02-21T00:36:44.638Z", - ], - "emails" => [ - [ - "value" => "yoon@seri.com", - "type" => "work", - "primary" => true - ] - ], - ], - "customAttributes" => [ - "fullName" => "Yoon Seri" - ], - "firstName" => "Yoon", - "email" => "yoon@seri.com", - "emails" => [ - [ - "primary" => true, - "type" => "work", - "value" => "yoon@seri.com" - ] - ], - "username" => "yoon@seri.com", - "lastName" => "Seri", - "jobTitle" => "Software Engineer", - "state" => "active", - "idpId" => null, - "role" => new RoleResponse("admin"), - "roles" => [ - new RoleResponse("admin"), - ], - "groups" => null, - "directoryId" => "dir_123", - "organizationId" => "org_123", - ]; - } -} diff --git a/tests/WorkOS/MFATest.php b/tests/WorkOS/MFATest.php deleted file mode 100644 index e5c61680..00000000 --- a/tests/WorkOS/MFATest.php +++ /dev/null @@ -1,384 +0,0 @@ -traitSetUp(); - - $this->withApiKeyAndClientId(); - $this->mfa = new MFA(); - } - - public function testEnrollFactorTotp() - { - $type = "totp"; - $path = "auth/factors/enroll"; - $totpIssuer = "test"; - $totpUser = "ricksanchez"; - $phoneNumber = null; - $params = [ - "type" => $type, - "totp_issuer" => $totpIssuer, - "totp_user" => $totpUser, - "phone_number" => $phoneNumber - ]; - - $result = $this->enrollFactorTotpResponseFixture(); - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $enrollFactorTotp = $this->mfa->enrollFactor($type, $totpIssuer, $totpUser, null); - $enrollFactorTotpFixture = $this->enrollFactorTotpFixture(); - - $this->assertSame($enrollFactorTotpFixture, $enrollFactorTotp->toArray()); - } - - public function testEnrollFactorSms() - { - $type = "sms"; - $path = "auth/factors/enroll"; - $totpIssuer = null; - $totpUser = null; - $phoneNumber = "1234567890"; - $params = [ - "type" => $type, - "totp_issuer" => $totpIssuer, - "totp_user" => $totpUser, - "phone_number" => $phoneNumber - ]; - - $result = $this->enrollFactorSmsResponseFixture(); - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $enrollFactorSms = $this->mfa->enrollFactor($type, $totpIssuer, $totpUser, $phoneNumber); - $enrollFactorSmsFixture = $this->enrollFactorSmsFixture(); - - $this->assertSame($enrollFactorSmsFixture, $enrollFactorSms->toArray()); - } - - public function testChallengeFactor() - { - $authenticationFactorId = "auth_factor_01FXNWW32G7F3MG8MYK5D1HJJM"; - $path = "auth/factors/{$authenticationFactorId}/challenge"; - $smsTemplate = "test"; - $params = [ - "sms_template" => $smsTemplate - ]; - - $result = $this->challengeFactorResponseFixture(); - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $challengeFactor = $this->mfa->challengeFactor($authenticationFactorId, $smsTemplate); - $challengeFactorResponseFixture = $this->challengeFactorFixture(); - - $this->assertSame($challengeFactorResponseFixture, $challengeFactor->toArray()); - } - - public function testVerifyFactor() - { - $authenticationChallengeId = "auth_challenge_01FXNX3BTZPPJVKF65NNWGRHZJ"; - $path = "auth/challenges/{$authenticationChallengeId}/verify"; - $code = "123456"; - $params = [ - "code" => $code - ]; - - $result = $this->verifyFactorResponseFixture(); - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $verifyFactor = $this->mfa->verifyFactor($authenticationChallengeId, $code); - $verifyFactorResponseFixture = $this->verifyFactorFixture(); - - $this->assertSame($verifyFactorResponseFixture, $verifyFactor->toArray()); - } - - public function testVerifyChallenge() - { - $authenticationChallengeId = "auth_challenge_01FXNX3BTZPPJVKF65NNWGRHZJ"; - $path = "auth/challenges/{$authenticationChallengeId}/verify"; - $code = "123456"; - $params = [ - "code" => $code - ]; - - $result = $this->verifyChallengeResponseFixture(); - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $verifyChallenge = $this->mfa->verifyChallenge($authenticationChallengeId, $code); - $verifyChallengeResponseFixture = $this->verifyChallengeFixture(); - - $this->assertSame($verifyChallengeResponseFixture, $verifyChallenge->toArray()); - } - - public function testGetFactor() - { - $authenticationFactorId = "auth_factor_01FXNWW32G7F3MG8MYK5D1HJJM"; - $getFactorPath = "auth/factors/{$authenticationFactorId}"; - - $result = $this->getFactorResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $getFactorPath, - null, - null, - true, - $result - ); - - $factor = $this->mfa->getFactor($authenticationFactorId); - $factorFixture = $this->getfactorFixture(); - - $this->assertSame($factorFixture, $factor->toArray()); - } - - public function testDeleteFactor() - { - $authenticationFactorId = "auth_factor_01FXNWW32G7F3MG8MYK5D1HJJM"; - $deleteFactorPath = "auth/factors/{$authenticationFactorId}"; - $responseCode = 200; - - $this->mockRequest( - Client::METHOD_DELETE, - $deleteFactorPath, - null, - null, - true, - null, - null, - $responseCode - ); - - $response = $this->mfa->deleteFactor($authenticationFactorId); - $this->assertSame(200, $responseCode); - } - - // Fixtures - - private function enrollFactorTotpResponseFixture() - { - return json_encode([ - "object" => "authentication_factor", - "id" => "auth_factor_01FXNWW32G7F3MG8MYK5D1HJJM", - "created_at" => "2022-03-08T23:12:20.157Z", - "updated_at" => "2022-03-08T23:12:20.157Z", - "type" => "totp", - "totp" => [ - "qr_code" => "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAApAAAAKQCAYAAAAotUpQAAAAAklEQVR4AewaftIAABPuSURBVO3B0Y0s2w0EsCrh5Z+y7BR0z0djsCSbZMPP2t18qW2+tLt50TYvdjdfaptftrt50TYvdjcv2obv7G5etM2L3c2X2ubF7uZLbcPvmgAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4GACAAAH/+XR7oZ/1zZ8Z3fzom1e7G5e7G5etA3f2d38srb5ZbubL7XNi93Ni7Z5sbv50u6Gf9c2LyYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwX/5WNv8st3NL2ubL+1uXrTNl3Y3X2qbX9Y2f1nb/GW7mxdt86XdDb+rbX7Z7uZLEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAODgv8CD3c2Xdjcv2uYv2938ZW3zpd3NX9Y2L3Y3/LvdDfyrCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHDwX+BB27zY3Xxpd/PLdjcv2ubF7uZF2/xlbfPLdjcvdjdfaptf1jZf2t3wd00AAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAg//ysd0Nv2t388va5sXu5kXbvNjdvNjdfGl386W2+WW7mxdt88va5pftbvjO7oZ/NwEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAO/sujtoF/1TYvdjf8u7Z5sbt50TYvdjdf2t28aJu/rG1e7G5etM2L3c2Ltnmxu3nRNi92N19qG74zAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA7+293Ar2qbF7ubL+1u+F1t82J386XdzZd2N1/a3Xxpd/OX7W74XRMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgoEk2D3Y3L9qGf7e7+cva5sXu5kXb8J3dzYu2ebG7edE2L3Y3X2qbF7ubF23zl+1uflnb8O92N1+aAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAfd/8uDtvllu5sXbfNid/OibV7sbv6ytnmxu/nL2ubF7uZF23xpd/Oibb60u/nL2ubF7uZF23xpd/Oibb60u/lS23xpd/OibV5MAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIPu/+VDbfOl3c2LtuE7u5svtc1ftrt50TYvdjcv2uaX7W5+Wdt8aXfDv2sb/q4JAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcPBfftzu5pftbl60zYvdzV/WNl/a3bxom7+sbV7sbl60zZfa5ku7m1/WNi92N19qmxe7m1+2u3nRNl/a3bxomy9NAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMm2fyw3c2LtuF37W6+1DZf2t28aJsXu5sXbfNid/OibV7sbn5Z2/Cd3c2Ltnmxu3nRNi92Ny/a5sXu5kXb/LLdzYsJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcND9vzxomy/tbl60zZd2Ny/a5pftbl60zV+2u3nRNl/a3fyytnmxu/llbfNid/OibV7sbvhO2/yy3c2X2uZLEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOCgSTYf2t38srb50u7mRdu82N28aJsXu5sXbfNid/OltvnS7uZF27zY3bxoG/hXu5sXbfNid/OXtc2Xdjcv2uZLu5sXEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOCg+3950DYvdjcv2ubF7uYva5sXuxv+Xdu82N28aJsXuxu+0zYvdjcv2ubF7uZF27zY3fyytnmxu/llbfPLdjcv2ubF7ubFBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADj4L492Ny/a5ktt82J386JtXuxuXuxuXrTNi93Nl9rmS7ubF23zy9rmxe7mRdu82N38ZbubF23zpbb5y9rmxe7ml+1uvtQ2v2wCAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHPzXNi92N79sd/OibV7sbl60Db+rbf6y3c2Ltnmxu/lS27zY3bxomxe7my/tbr7UNi92Ny/a5sXu5ktt86W2ebG7+dLu5kXbvJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAAB//lY7ubv6xtvrS7edE2v2x386JtvrS7edE2X2ob/l3b/LLdzZfa5i9rmy/tbl60Df9ud/NiAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABz8l4+1zV+2u/lS23ypbV7sbvhdu5sXbfPLdjdfapsvtc2Xdjcv2uZF27zY3fyytnmxu3nRNi/a5sXu5pdNAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIPu/+VDbfOl3c2Ltvllu5sXbfOl3c2X2uYv2928aBu+s7v5y9rmxe7mS23zYnfzy9rmxe7mS23zYnfzpQkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABw8F/+uLb50u7mL9vdvGibX7a7+WVt82J386JtXuxuflnbfKltvrS7+VLb/LK2+WW7m7+sbb40AQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA7+axu+0zYvdjcv2ubF7uaX7W5etM2X2uaXtc0va5sXu5sXu5u/rG1+2e7ml7XNL2ubL+1uftkEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4GACAAAHEwAAOOj+Xz7UNi92Ny/a5sXu5ktt82J386JtXuxu/rK2ebG7+WVt86XdzYu2+dLu5pe1zYvdzYu2ebG7+VLb8O92N19qm182AQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA7+y49rmxe7mxdt88va5sXu5kXbvNjdfKltvtQ2L3Y3L9rmxe7mRdu8aJsXu5sXbfPL2uYva5sXu5tftrt50Ta/rG2+tLt50TYvJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBf/nY7uZLbfOl3c2LtvnL2ubF7ubF7uZLbfOl3c2LtvllbfOltnmxu3mxu3nRNr9sd/PLdjcv2uZLu5tftrv5ZRMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADg4L+2+dLu5kXbvNjdfKlt+He7mxdt82J386JtXuxuXrTNi93Ni93Nl9rmS7ubX9Y2L3Y3L9rmS23zpd3NL9vdvGibL+1uvtQ2L3Y3LyYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwX95tLt50TYvdjdfapsXu5sXbcPf1TYvdjcv2ubF7uYva5sXu5sv7W5etM2L3c2Ltnmxu3nRNn9Z27zY3XypbV7sbr7UNi8mAABwMAEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwEGTbD60u/nL2uZLu5sXbfOl3Q3faZsXu5tf1jYvdje/rG2+tLv5Utu82N28aJu/bHfzpbb5yyYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAQZNs+Ge7my+1zZd2Ny/a5sXu5kXbvNjd/LK2+WW7mxdt82J388va5sXu5kXb/LLdzZfa5sXu5kttw7/b3bxomxcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4KBJNg92N7+sbV7sbl60zV+2u3nRNi92Ny/a5sXu5ktt86XdzYu2ebG7edE2L3Y3/K62+ct2N19qmy/tbl60zZd2Ny8mAABwMAEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwEGTbB7sbvi72uZLu5svtc2L3c0va5u/bHfzom1e7G5etM0v2928aJsXu5sXbfNid/Oltnmxu/llbfNid/OltnkxAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA7+y49rmxe7my+1zZd2Ny92N7+sbV7sbl60DX/X7uaX7W5etM0va5svtc0va5tftrt50TZf2t28mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4GACAAAH3f8Lf1bb8O92N19qmxe7mxdt82J386JtXuxuXrTNl3Y3L9rml+1u/rK2+dLu5pe1zYvdzYu2+WUTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4KBJNvys3c0va5sXu5sXbcN3djcv2uaX7W6+1Db8u93Ni7Z5sbt50TYvdjcv2ubF7uZF27zY3fxlEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOCgSTYPdjf8u7Z5sbt50TYvdjdfapsXuxv+Xdt8aXfzpbbh3+1uXrTNi93NX9Y2L3Y3v6xt+HcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4OC/fKxtftnu5i9rm1/WNn/Z7ubF7uZLbfNid/Ol3c2LtvnS7uZF27zY3bxomxe7mxdt88va5i/b3bxomy/tbl5MAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIP/An/Y7uZF23xpd/Oibf6ytvlS23xpd/Ol3c2Xdjdf2t18qW1e7G74XW3zYgIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAc/Bf4w9rml7XNi93NX9Y2v2x386JtXuxuXrTNL9vdfKltXuxuXrTNX7a7+WW7mxcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4OC/fGx3w3d2N39Z23xpd/OibV60zYvdzZfa5sXu5kXbvNjdvGibX7a7+cva5sXu5kXbfGl386W2+dLu5kXbfGkCAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHDTJhp+1u3nRNl/a3bxomy/tbn5Z2/yy3c0va5sXu5sXbfOX7W5etM2L3c2Ltnmxu/nL2uaX7W6+NAEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAO/gfiF4JV0SXN7wAAAABJRU5ErkJggg==", - "secret" => "JJWBYBLLH5TRKYZEGMREU6DRKFRVMTCV", - "uri" => "otpauth://totp/testytest:berniesanders?secret=JJWBYBLLH5TRKYZEGMREU6DRKFRVMTCV&issuer=testytest" - ] - ]); - } - - private function enrollFactorTotpFixture() - { - return [ - "object" => "authentication_factor", - "id" => "auth_factor_01FXNWW32G7F3MG8MYK5D1HJJM", - "createdAt" => "2022-03-08T23:12:20.157Z", - "updatedAt" => "2022-03-08T23:12:20.157Z", - "type" => "totp", - "totp" => [ - "qr_code" => "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAApAAAAKQCAYAAAAotUpQAAAAAklEQVR4AewaftIAABPuSURBVO3B0Y0s2w0EsCrh5Z+y7BR0z0djsCSbZMPP2t18qW2+tLt50TYvdjdfaptftrt50TYvdjcv2obv7G5etM2L3c2X2ubF7uZLbcPvmgAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4GACAAAH/+XR7oZ/1zZ8Z3fzom1e7G5e7G5etA3f2d38srb5ZbubL7XNi93Ni7Z5sbv50u6Gf9c2LyYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwX/5WNv8st3NL2ubL+1uXrTNl3Y3X2qbX9Y2f1nb/GW7mxdt86XdDb+rbX7Z7uZLEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAODgv8CD3c2Xdjcv2uYv2938ZW3zpd3NX9Y2L3Y3/LvdDfyrCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHDwX+BB27zY3Xxpd/PLdjcv2ubF7uZF2/xlbfPLdjcvdjdfaptf1jZf2t3wd00AAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAg//ysd0Nv2t388va5sXu5kXbvNjdvNjdfGl386W2+WW7mxdt88va5pftbvjO7oZ/NwEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAO/sujtoF/1TYvdjf8u7Z5sbt50TYvdjdf2t28aJu/rG1e7G5etM2L3c2Ltnmxu3nRNi92N19qG74zAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA7+293Ar2qbF7ubL+1u+F1t82J386XdzZd2N1/a3Xxpd/OX7W74XRMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgoEk2D3Y3L9qGf7e7+cva5sXu5kXb8J3dzYu2ebG7edE2L3Y3X2qbF7ubF23zl+1uflnb8O92N1+aAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAfd/8uDtvllu5sXbfNid/OibV7sbv6ytnmxu/nL2ubF7uZF23xpd/Oibb60u/nL2ubF7uZF23xpd/Oibb60u/lS23xpd/OibV5MAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIPu/+VDbfOl3c2LtuE7u5svtc1ftrt50TYvdjcv2uaX7W5+Wdt8aXfDv2sb/q4JAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcPBfftzu5pftbl60zYvdzV/WNl/a3bxom7+sbV7sbl60zZfa5ku7m1/WNi92N19qmxe7m1+2u3nRNl/a3bxomy9NAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMm2fyw3c2LtuF37W6+1DZf2t28aJsXu5sXbfNid/OibV7sbn5Z2/Cd3c2Ltnmxu3nRNi92Ny/a5sXu5kXb/LLdzYsJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcND9vzxomy/tbl60zZd2Ny/a5pftbl60zV+2u3nRNl/a3fyytnmxu/llbfNid/OibV7sbvhO2/yy3c2X2uZLEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOCgSTYf2t38srb50u7mRdu82N28aJsXu5sXbfNid/OltvnS7uZF27zY3bxoG/hXu5sXbfNid/OXtc2Xdjcv2uZLu5sXEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOCg+3950DYvdjcv2ubF7uYva5sXuxv+Xdu82N28aJsXuxu+0zYvdjcv2ubF7uZF27zY3fyytnmxu/llbfPLdjcv2ubF7ubFBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADj4L492Ny/a5ktt82J386JtXuxuXuxuXrTNi93Nl9rmS7ubF23zy9rmxe7mRdu82N38ZbubF23zpbb5y9rmxe7ml+1uvtQ2v2wCAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHPzXNi92N79sd/OibV7sbl60Db+rbf6y3c2Ltnmxu/lS27zY3bxomxe7my/tbr7UNi92Ny/a5sXu5ktt86W2ebG7+dLu5kXbvJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAAB//lY7ubv6xtvrS7edE2v2x386JtvrS7edE2X2ob/l3b/LLdzZfa5i9rmy/tbl60Df9ud/NiAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABz8l4+1zV+2u/lS23ypbV7sbvhdu5sXbfPLdjdfapsvtc2Xdjcv2uZF27zY3fyytnmxu3nRNi/a5sXu5pdNAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIPu/+VDbfOl3c2Ltvllu5sXbfOl3c2X2uYv2928aBu+s7v5y9rmxe7mS23zYnfzy9rmxe7mS23zYnfzpQkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABw8F/+uLb50u7mL9vdvGibX7a7+WVt82J386JtXuxuflnbfKltvrS7+VLb/LK2+WW7m7+sbb40AQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA7+axu+0zYvdjcv2ubF7uaX7W5etM2X2uaXtc0va5sXu5sXu5u/rG1+2e7ml7XNL2ubL+1uftkEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4GACAAAHEwAAOOj+Xz7UNi92Ny/a5sXu5ktt82J386JtXuxu/rK2ebG7+WVt86XdzYu2+dLu5pe1zYvdzYu2ebG7+VLb8O92N19qm182AQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA7+y49rmxe7mxdt88va5sXu5kXbvNjdfKltvtQ2L3Y3L9rmxe7mRdu8aJsXu5sXbfPL2uYva5sXu5tftrt50Ta/rG2+tLt50TYvJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBf/nY7uZLbfOl3c2LtvnL2ubF7ubF7uZLbfOl3c2LtvllbfOltnmxu3mxu3nRNr9sd/PLdjcv2uZLu5tftrv5ZRMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADg4L+2+dLu5kXbvNjdfKlt+He7mxdt82J386JtXuxuXrTNi93Ni93Nl9rmS7ubX9Y2L3Y3L9rmS23zpd3NL9vdvGibL+1uvtQ2L3Y3LyYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwX95tLt50TYvdjdfapsXu5sXbcPf1TYvdjcv2ubF7uYva5sXu5sv7W5etM2L3c2Ltnmxu3nRNn9Z27zY3XypbV7sbr7UNi8mAABwMAEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwEGTbD60u/nL2uZLu5sXbfOl3Q3faZsXu5tf1jYvdje/rG2+tLv5Utu82N28aJu/bHfzpbb5yyYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAQZNs+Ge7my+1zZd2Ny/a5sXu5kXbvNjd/LK2+WW7mxdt82J388va5sXu5kXb/LLdzZfa5sXu5kttw7/b3bxomxcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4KBJNg92N7+sbV7sbl60zV+2u3nRNi92Ny/a5sXu5ktt86XdzYu2ebG7edE2L3Y3/K62+ct2N19qmy/tbl60zZd2Ny8mAABwMAEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwEGTbB7sbvi72uZLu5svtc2L3c0va5u/bHfzom1e7G5etM0v2928aJsXu5sXbfNid/Oltnmxu/llbfNid/OltnkxAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA7+y49rmxe7my+1zZd2Ny92N7+sbV7sbl60DX/X7uaX7W5etM0va5svtc0va5tftrt50TZf2t28mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4GACAAAH3f8Lf1bb8O92N19qmxe7mxdt82J386JtXuxuXrTNl3Y3L9rml+1u/rK2+dLu5pe1zYvdzYu2+WUTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4KBJNvys3c0va5sXu5sXbcN3djcv2uaX7W6+1Db8u93Ni7Z5sbt50TYvdjcv2ubF7uZF27zY3fxlEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOCgSTYPdjf8u7Z5sbt50TYvdjdfapsXuxv+Xdt8aXfzpbbh3+1uXrTNi93NX9Y2L3Y3v6xt+HcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4OC/fKxtftnu5i9rm1/WNn/Z7ubF7uZLbfNid/Ol3c2LtvnS7uZF27zY3bxomxe7mxdt88va5i/b3bxomy/tbl5MAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIP/An/Y7uZF23xpd/Oibf6ytvlS23xpd/Ol3c2Xdjdf2t18qW1e7G74XW3zYgIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAc/Bf4w9rml7XNi93NX9Y2v2x386JtXuxuXrTNL9vdfKltXuxuXrTNX7a7+WW7mxcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4OC/fGx3w3d2N39Z23xpd/OibV60zYvdzZfa5sXu5kXbvNjdvGibX7a7+cva5sXu5kXbfGl386W2+dLu5kXbfGkCAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHDTJhp+1u3nRNl/a3bxomy/tbn5Z2/yy3c0va5sXu5sXbfOX7W5etM2L3c2Ltnmxu/nL2uaX7W6+NAEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAO/gfiF4JV0SXN7wAAAABJRU5ErkJggg==", - "secret" => "JJWBYBLLH5TRKYZEGMREU6DRKFRVMTCV", - "uri" => "otpauth://totp/testytest:berniesanders?secret=JJWBYBLLH5TRKYZEGMREU6DRKFRVMTCV&issuer=testytest" - ] - ]; - } - - private function enrollFactorSmsResponseFixture() - { - return json_encode([ - "object" => "authentication_factor", - "id" => "auth_factor_01FXK4YXEZEEQ0AYNJE5PA7FQR", - "created_at" => "2022-03-08T23:12:20.157Z", - "updated_at" => "2022-03-08T23:12:20.157Z", - "type" => "sms", - "sms" => [ - "phone_number" => "+7208675309" - ] - ]); - } - - private function enrollFactorSmsFixture() - { - return [ - "object" => "authentication_factor", - "id" => "auth_factor_01FXK4YXEZEEQ0AYNJE5PA7FQR", - "createdAt" => "2022-03-08T23:12:20.157Z", - "updatedAt" => "2022-03-08T23:12:20.157Z", - "type" => "sms", - "sms" => [ - "phone_number" => "+7208675309" - ] - ]; - } - - private function challengeFactorResponseFixture() - { - return json_encode([ - "object" => "authentication_challenge", - "id" => "auth_challenge_01FXNX3BTZPPJVKF65NNWGRHZJ", - "created_at" => "2022-03-08T23:16:18.532Z", - "updated_at" => "2022-03-08T23:16:18.532Z", - "expires_at" => "2022-03-08T23:16:18.532Z", - "authentication_factor_id" => "auth_factor_01FXNWW32G7F3MG8MYK5D1HJJM" - ]); - } - - private function challengeFactorFixture() - { - return [ - "object" => "authentication_challenge", - "id" => "auth_challenge_01FXNX3BTZPPJVKF65NNWGRHZJ", - "createdAt" => "2022-03-08T23:16:18.532Z", - "updatedAt" => "2022-03-08T23:16:18.532Z", - "expiresAt" => "2022-03-08T23:16:18.532Z", - "authenticationFactorId" => "auth_factor_01FXNWW32G7F3MG8MYK5D1HJJM" - ]; - } - - private function verifyFactorResponseFixture() - { - return json_encode([ - "challenge" => [ - "object" => "authentication_challenge", - "id" => "auth_challenge_01FXNX3BTZPPJVKF65NNWGRHZJ", - "created_at" => "2022-03-08T23:16:18.532Z", - "updated_at" => "2022-03-08T23:16:18.532Z", - "expires_at" => "2022-02-15T15:36:53.279Z", - "authentication_factor_id" => "auth_factor_01FXNWW32G7F3MG8MYK5D1HJJM", - ], - "valid" => "true" - ]); - } - - private function verifyFactorFixture() - { - return [ - "challenge" => [ - "object" => "authentication_challenge", - "id" => "auth_challenge_01FXNX3BTZPPJVKF65NNWGRHZJ", - "created_at" => "2022-03-08T23:16:18.532Z", - "updated_at" => "2022-03-08T23:16:18.532Z", - "expires_at" => "2022-02-15T15:36:53.279Z", - "authentication_factor_id" => "auth_factor_01FXNWW32G7F3MG8MYK5D1HJJM", - ], - "valid" => "true" - ]; - } - - private function verifyChallengeResponseFixture() - { - return json_encode([ - "challenge" => [ - "object" => "authentication_challenge", - "id" => "auth_challenge_01FXNX3BTZPPJVKF65NNWGRHZJ", - "created_at" => "2022-03-08T23:16:18.532Z", - "updated_at" => "2022-03-08T23:16:18.532Z", - "expires_at" => "2022-02-15T15:36:53.279Z", - "authentication_factor_id" => "auth_factor_01FXNWW32G7F3MG8MYK5D1HJJM", - ], - "valid" => "true" - ]); - } - - private function verifyChallengeFixture() - { - return [ - "challenge" => [ - "object" => "authentication_challenge", - "id" => "auth_challenge_01FXNX3BTZPPJVKF65NNWGRHZJ", - "created_at" => "2022-03-08T23:16:18.532Z", - "updated_at" => "2022-03-08T23:16:18.532Z", - "expires_at" => "2022-02-15T15:36:53.279Z", - "authentication_factor_id" => "auth_factor_01FXNWW32G7F3MG8MYK5D1HJJM", - ], - "valid" => "true" - ]; - } - - private function getFactorResponseFixture() - { - return json_encode([ - "object" => "authentication_factor", - "id" => "auth_factor_01FXNWW32G7F3MG8MYK5D1HJJM", - "created_at" => "2022-03-08T23:12:20.157Z", - "updated_at" => "2022-03-08T23:12:20.157Z", - "type" => "totp", - "totp" => [ - "issuer" => "authentication_factor_issuer", - "user" => "user@test.com" - ] - ]); - } - - private function getFactorFixture() - { - return [ - "object" => "authentication_factor", - "id" => "auth_factor_01FXNWW32G7F3MG8MYK5D1HJJM", - "createdAt" => "2022-03-08T23:12:20.157Z", - "updatedAt" => "2022-03-08T23:12:20.157Z", - "type" => "totp", - "totp" => [ - "issuer" => "authentication_factor_issuer", - "user" => "user@test.com" - ] - ]; - } -} diff --git a/tests/WorkOS/OrganizationsTest.php b/tests/WorkOS/OrganizationsTest.php deleted file mode 100644 index 4363ab56..00000000 --- a/tests/WorkOS/OrganizationsTest.php +++ /dev/null @@ -1,568 +0,0 @@ -traitSetUp(); - - $this->withApiKey(); - $this->organizations = new Organizations(); - } - - public function testCreateOrganizationWithDomains() - { - $organizationsPath = "organizations"; - - $result = $this->createOrganizationResponseFixture(); - - $params = [ - "name" => "Organization Name", - "domains" => array("example.com"), - ]; - - $this->mockRequest( - Client::METHOD_POST, - $organizationsPath, - null, - $params, - true, - $result - ); - - $organization = $this->organizationFixture(); - - $response = $this->organizations->createOrganization("Organization Name", array("example.com")); - $this->assertSame($organization, $response->toArray()); - } - - public function testCreateOrganizationWithDomainData() - { - $organizationsPath = "organizations"; - - $result = $this->createOrganizationResponseFixture(); - - $params = [ - "name" => "Organization Name", - "domain_data" => array([ - "domain" => "example.com", - "state" => "verified", - ]), - ]; - - $this->mockRequest( - Client::METHOD_POST, - $organizationsPath, - null, - $params, - true, - $result - ); - - $organization = $this->organizationFixture(); - - $response = $this->organizations->createOrganization( - "Organization Name", - null, - null, - null, - array(["domain" => "example.com", "state" => "verified"]), - ); - $this->assertSame($organization, $response->toArray()); - } - - public function testUpdateOrganizationWithDomainData() - { - $organizationsPath = "organizations/org_01EHQMYV6MBK39QC5PZXHY59C3"; - - $result = $this->createOrganizationResponseFixture(); - - $params = [ - "name" => null, - "domain_data" => array([ - "domain" => "example.com", - "state" => "verified", - ]), - ]; - - $this->mockRequest( - Client::METHOD_PUT, - $organizationsPath, - null, - $params, - true, - $result - ); - - $organization = $this->organizationFixture(); - - $response = $this->organizations->updateOrganization( - "org_01EHQMYV6MBK39QC5PZXHY59C3", - null, - null, - null, - array(["domain" => "example.com", "state" => "verified"]), - ); - $this->assertSame($organization, $response->toArray()); - } - - public function testCreateOrganizationSendsIdempotencyKey() - { - $organizationsPath = "organizations"; - $idempotencyKey = "idempotencyKey123"; - $result = $this->createOrganizationResponseFixture(); - - $params = [ - "name" => "Organization Name", - "domains" => array("example.com"), - ]; - - $this->mockRequest( - Client::METHOD_POST, - $organizationsPath, - array("Authorization: Bearer pk_secretsauce", 'Idempotency-Key: idempotencyKey123'), - $params, - false, - $result - ); - - $response = $this->organizations->createOrganization("Organization Name", array("example.com"), null, $idempotencyKey); - $response2 = $this->organizations->createOrganization("Organization Name", array("example.com"), null, $idempotencyKey); - - $this->assertSame($response2->toArray()["id"], $response->toArray()["id"]); - } - - - public function testListOrganizations() - { - $organizationsPath = "organizations"; - $params = [ - "limit" => Organizations::DEFAULT_PAGE_SIZE, - "before" => null, - "after" => null, - "domains" => null, - "order" => null - ]; - - $result = $this->organizationsResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $organizationsPath, - null, - $params, - true, - $result - ); - - $organization = $this->organizationFixture(); - - list($before, $after, $organizations) = $this->organizations->listOrganizations(); - $this->assertSame($organization, $organizations[0]->toArray()); - } - - public function testListOrganizationsPaginatedResourceAccessPatterns() - { - $organizationsPath = "organizations"; - $params = [ - "limit" => Organizations::DEFAULT_PAGE_SIZE, - "before" => null, - "after" => null, - "domains" => null, - "order" => null - ]; - - $result = $this->organizationsResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $organizationsPath, - null, - $params, - true, - $result - ); - - // Test 1: Bare destructuring (indexed) - [$before1, $after1, $organizations1] = $this->organizations->listOrganizations(); - $this->assertSame("before-id", $before1); - $this->assertNull($after1); - $this->assertIsArray($organizations1); - $this->assertCount(3, $organizations1); - - // Mock the request again for the next test - $this->mockRequest( - Client::METHOD_GET, - $organizationsPath, - null, - $params, - true, - $result - ); - - // Test 2: Named destructuring - ["before" => $before2, "after" => $after2, "organizations" => $organizations2] = $this->organizations->listOrganizations(); - $this->assertSame("before-id", $before2); - $this->assertNull($after2); - $this->assertIsArray($organizations2); - $this->assertCount(3, $organizations2); - - // Mock the request again for the next test - $this->mockRequest( - Client::METHOD_GET, - $organizationsPath, - null, - $params, - true, - $result - ); - - // Test 3: Fluent access - $response = $this->organizations->listOrganizations(); - $this->assertSame("before-id", $response->before); - $this->assertNull($response->after); - $this->assertIsArray($response->organizations); - $this->assertCount(3, $response->organizations); - - // Test 4: Generic data accessor - $this->assertIsArray($response->data); - $this->assertSame($response->organizations, $response->data); - } - - public function testListOrganizationRoles() - { - $organizationRolesPath = "organizations/org_01EHQMYV6MBK39QC5PZXHY59C3/roles"; - - $result = $this->organizationRolesResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $organizationRolesPath, - null, - null, - true, - $result - ); - - $role = $this->roleFixture(); - - list($roles) = $this->organizations->listOrganizationRoles("org_01EHQMYV6MBK39QC5PZXHY59C3"); - $this->assertSame($role, $roles[0]->toArray()); - } - - public function testListOrganizationFeatureFlags() - { - $featureFlagsPath = "organizations/org_01EHQMYV6MBK39QC5PZXHY59C3/feature-flags"; - - $result = $this->featureFlagsResponseFixture(); - - $params = [ - "limit" => 10, - "before" => null, - "after" => null, - "order" => null - ]; - - $this->mockRequest( - Client::METHOD_GET, - $featureFlagsPath, - null, - $params, - true, - $result - ); - - $featureFlag = $this->featureFlagFixture(); - - list($before, $after, $featureFlags) = $this->organizations->listOrganizationFeatureFlags("org_01EHQMYV6MBK39QC5PZXHY59C3"); - $this->assertSame($featureFlag, $featureFlags[0]->toArray()); - } - - public function testListOrganizationFeatureFlagsPaginatedResourceAccessPatterns() - { - $featureFlagsPath = "organizations/org_01EHQMYV6MBK39QC5PZXHY59C3/feature-flags"; - $result = $this->featureFlagsResponseFixture(); - $params = [ - "limit" => 10, - "before" => null, - "after" => null, - "order" => null - ]; - - $this->mockRequest( - Client::METHOD_GET, - $featureFlagsPath, - null, - $params, - true, - $result - ); - - // Test 1: Bare destructuring (indexed) - [$before1, $after1, $flags1] = $this->organizations->listOrganizationFeatureFlags("org_01EHQMYV6MBK39QC5PZXHY59C3"); - $this->assertSame("", $before1); - $this->assertSame("", $after1); - $this->assertIsArray($flags1); - $this->assertCount(3, $flags1); - - // Mock the request again for the next test - $this->mockRequest( - Client::METHOD_GET, - $featureFlagsPath, - null, - $params, - true, - $result - ); - - // Test 2: Named destructuring - ["before" => $before2, "after" => $after2, "feature_flags" => $flags2] = $this->organizations->listOrganizationFeatureFlags("org_01EHQMYV6MBK39QC5PZXHY59C3"); - $this->assertSame("", $before2); - $this->assertSame("", $after2); - $this->assertIsArray($flags2); - $this->assertCount(3, $flags2); - - // Mock the request again for the next test - $this->mockRequest( - Client::METHOD_GET, - $featureFlagsPath, - null, - $params, - true, - $result - ); - - // Test 3: Fluent access - $response = $this->organizations->listOrganizationFeatureFlags("org_01EHQMYV6MBK39QC5PZXHY59C3"); - $this->assertSame("", $response->before); - $this->assertSame("", $response->after); - $this->assertIsArray($response->feature_flags); - $this->assertCount(3, $response->feature_flags); - - // Test 4: Generic data accessor - $this->assertIsArray($response->data); - $this->assertSame($response->feature_flags, $response->data); - } - - // Fixtures - - private function createOrganizationResponseFixture() - { - return json_encode([ - "name" => "Organization Name", - "object" => "organization", - "id" => "org_01EHQMYV6MBK39QC5PZXHY59C3", - "allow_profiles_outside_organization" => false, - "domains" => [ - [ - "object" => "organization_domain", - "id" => "org_domain_01EHQMYV71XT8H31WE5HF8YK4A", - "domain" => "example.com" - ] - ], - "external_id" => null, - "metadata" => [] - ]); - } - - private function organizationsResponseFixture() - { - return json_encode([ - "object" => "list", - "data" => [ - [ - "object" => "organization", - "id" => "org_01EHQMYV6MBK39QC5PZXHY59C3", - "name" => "Organization Name", - "allow_profiles_outside_organization" => false, - "domains" => [ - [ - "object" => "organization_domain", - "id" => "org_domain_01EHQMYV71XT8H31WE5HF8YK4A", - "domain" => "example.com" - ] - ], - "external_id" => null, - "metadata" => [] - ], - [ - "object" => "organization", - "id" => "org_01EHQMVDTC2GRAHFCCRNTSKH46", - "name" => "example2.com", - "allow_profiles_outside_organization" => false, - "domains" => [ - [ - "object" => "organization_domain", - "id" => "org_domain_01EHQMVDTZVA27PK614ME4YK7V", - "domain" => "example2.com" - ] - ], - "external_id" => null, - "metadata" => [] - ], - [ - "object" => "organization", - "id" => "org_01EGP9Z6RY2J6YE0ZV57CGEXV2", - "name" => "example5.com", - "allow_profiles_outside_organization" => false, - "domains" => [ - [ - "object" => "organization_domain", - "id" => "org_domain_01EGP9Z6S6HVQ5CPD152GJBEA5", - "domain" => "example5.com" - ] - ], - "external_id" => null, - "metadata" => [] - ] - ], - "list_metadata" => [ - "before" => "before-id", - "after" => null - ] - ]); - } - - private function organizationFixture() - { - return [ - "id" => "org_01EHQMYV6MBK39QC5PZXHY59C3", - "name" => "Organization Name", - "allowProfilesOutsideOrganization" => false, - "domains" => [ - [ - "object" => "organization_domain", - "id" => "org_domain_01EHQMYV71XT8H31WE5HF8YK4A", - "domain" => "example.com" - ] - ], - "externalId" => null, - "metadata" => [] - ]; - } - - private function organizationRolesResponseFixture() - { - return json_encode([ - "object" => "list", - "data" => [ - [ - "object" => "role", - "id" => "role_01EHQMYV6MBK39QC5PZXHY59C2", - "name" => "Admin", - "slug" => "admin", - "description" => "Admin role", - "permissions" => ["posts:read", "posts:write"], - "resource_type_slug" => "organization", - "type" => "EnvironmentRole", - "created_at" => "2024-01-01T00:00:00.000Z", - "updated_at" => "2024-01-01T00:00:00.000Z" - ], - [ - "object" => "role", - "id" => "role_01EHQMYV6MBK39QC5PZXHY59C3", - "name" => "Member", - "slug" => "member", - "description" => "Member role", - "permissions" => [], - "resource_type_slug" => "organization", - "type" => "EnvironmentRole", - "created_at" => "2024-01-01T00:00:00.000Z", - "updated_at" => "2024-01-01T00:00:00.000Z" - ], - [ - "object" => "role", - "id" => "role_01EHQMYV6MBK39QC5PZXHY59C4", - "name" => "Org. Member", - "slug" => "org-member", - "description" => "Organization member role", - "permissions" => ["posts:read"], - "resource_type_slug" => "organization", - "type" => "OrganizationRole", - "created_at" => "2024-01-01T00:00:00.000Z", - "updated_at" => "2024-01-01T00:00:00.000Z" - ], - ], - ]); - } - - private function roleFixture() - { - return [ - "id" => "role_01EHQMYV6MBK39QC5PZXHY59C2", - "name" => "Admin", - "slug" => "admin", - "description" => "Admin role", - "permissions" => ["posts:read", "posts:write"], - "resource_type_slug" => "organization", - "type" => "EnvironmentRole", - "created_at" => "2024-01-01T00:00:00.000Z", - "updated_at" => "2024-01-01T00:00:00.000Z" - ]; - } - - private function featureFlagFixture() - { - return [ - "id" => "flag_01K2QR5YSWRB8J7GGAG05Y24HQ", - "slug" => "flag3", - "name" => "Flag3", - "description" => "", - "createdAt" => "2025-08-15T20:54:13.561Z", - "updatedAt" => "2025-08-15T20:54:13.561Z" - ]; - } - - private function featureFlagsResponseFixture() - { - return json_encode([ - "object" => "list", - "data" => [ - [ - "object" => "feature_flag", - "id" => "flag_01K2QR5YSWRB8J7GGAG05Y24HQ", - "slug" => "flag3", - "name" => "Flag3", - "description" => "", - "created_at" => "2025-08-15T20:54:13.561Z", - "updated_at" => "2025-08-15T20:54:13.561Z" - ], - [ - "object" => "feature_flag", - "id" => "flag_01K2QR5HGK2HQVFDZ4T60GWGVD", - "slug" => "flag2", - "name" => "Flag2", - "description" => "", - "created_at" => "2025-08-15T20:53:59.952Z", - "updated_at" => "2025-08-15T20:53:59.952Z" - ], - [ - "object" => "feature_flag", - "id" => "flag_01K2QKSH38RF4P9FV917PE24R3", - "slug" => "flag1", - "name" => "Flag1", - "description" => "", - "created_at" => "2025-08-15T19:37:32.005Z", - "updated_at" => "2025-08-15T19:37:32.005Z" - ], - ], - "list_metadata" => [ - "before" => "", - "after" => "" - ] - ]); - } -} diff --git a/tests/WorkOS/PaginatedResourceTest.php b/tests/WorkOS/PaginatedResourceTest.php deleted file mode 100644 index 92b48e90..00000000 --- a/tests/WorkOS/PaginatedResourceTest.php +++ /dev/null @@ -1,229 +0,0 @@ -makePaginatedResource(null, 'cursor_abc', ['a', 'b'], 'users'); - $this->assertInstanceOf(PaginatedResource::class, $resource); - } - - public function testConstructRejectsReservedDataKeyBefore() - { - $this->expectException(\InvalidArgumentException::class); - new PaginatedResource(null, null, [], 'before'); - } - - public function testConstructRejectsReservedDataKeyAfter() - { - $this->expectException(\InvalidArgumentException::class); - new PaginatedResource(null, null, [], 'after'); - } - - public function testConstructRejectsReservedDataKeyData() - { - $this->expectException(\InvalidArgumentException::class); - new PaginatedResource(null, null, [], 'data'); - } - - // -- Bare destructuring (numeric offsets) -- - - public function testBareDestructuring() - { - $resource = $this->makePaginatedResource('cur_before', 'cur_after', ['x', 'y']); - - [$before, $after, $items] = $resource; - - $this->assertSame('cur_before', $before); - $this->assertSame('cur_after', $after); - $this->assertSame(['x', 'y'], $items); - } - - public function testBareDestructuringWithNullCursors() - { - $resource = $this->makePaginatedResource(null, null, ['x']); - - [$before, $after, $items] = $resource; - - $this->assertNull($before); - $this->assertNull($after); - $this->assertSame(['x'], $items); - } - - // -- Named destructuring (string offsets) -- - - public function testNamedDestructuring() - { - $resource = $this->makePaginatedResource('b', 'a', [1, 2], 'users'); - - ["before" => $before, "after" => $after, "users" => $users] = $resource; - - $this->assertSame('b', $before); - $this->assertSame('a', $after); - $this->assertSame([1, 2], $users); - } - - public function testGenericDataKeyAccess() - { - $resource = $this->makePaginatedResource(null, null, [1, 2], 'users'); - - $this->assertSame($resource['data'], $resource['users']); - } - - // -- Fluent property access (__get) -- - - public function testFluentPropertyAccess() - { - $resource = $this->makePaginatedResource('b', 'a', [1], 'directories'); - - $this->assertSame('b', $resource->before); - $this->assertSame('a', $resource->after); - $this->assertSame([1], $resource->directories); - $this->assertSame([1], $resource->data); - } - - public function testFluentAccessUnknownPropertyReturnsNull() - { - $resource = $this->makePaginatedResource(null, null, []); - - $this->assertNull($resource->nonexistent); - $this->assertNull($resource->typo_property); - } - - // -- offsetExists -- - - public function testOffsetExistsNumericIndices() - { - $resource = $this->makePaginatedResource(); - - $this->assertTrue(isset($resource[0])); - $this->assertTrue(isset($resource[1])); - $this->assertTrue(isset($resource[2])); - $this->assertFalse(isset($resource[3])); - $this->assertFalse(isset($resource[-1])); - } - - public function testOffsetExistsStringKeys() - { - $resource = $this->makePaginatedResource(null, null, [], 'users'); - - $this->assertTrue(isset($resource['before'])); - $this->assertTrue(isset($resource['after'])); - $this->assertTrue(isset($resource['data'])); - $this->assertTrue(isset($resource['users'])); - $this->assertFalse(isset($resource['nonexistent'])); - } - - // -- __isset -- - - public function testIssetReturnsFalseForNullCursors() - { - $resource = $this->makePaginatedResource(null, null, []); - - $this->assertFalse(isset($resource->before)); - $this->assertFalse(isset($resource->after)); - } - - public function testIssetReturnsTrueForNonNullCursors() - { - $resource = $this->makePaginatedResource('b', 'a', []); - - $this->assertTrue(isset($resource->before)); - $this->assertTrue(isset($resource->after)); - } - - public function testIssetReturnsTrueForDataKey() - { - $resource = $this->makePaginatedResource(null, null, [], 'users'); - - $this->assertTrue(isset($resource->data)); - $this->assertTrue(isset($resource->users)); - } - - public function testIssetReturnsFalseForUnknownProperties() - { - $resource = $this->makePaginatedResource(); - - $this->assertFalse(isset($resource->nonexistent)); - } - - // -- Immutability -- - - public function testOffsetSetThrows() - { - $resource = $this->makePaginatedResource(); - - $this->expectException(\BadMethodCallException::class); - $resource[0] = 'value'; - } - - public function testOffsetUnsetThrows() - { - $resource = $this->makePaginatedResource(); - - $this->expectException(\BadMethodCallException::class); - unset($resource[0]); - } - - // -- Countable -- - - public function testCountReturnsDataItemCount() - { - $this->assertCount(0, $this->makePaginatedResource(null, null, [])); - $this->assertCount(3, $this->makePaginatedResource(null, null, ['a', 'b', 'c'])); - $this->assertCount(1, $this->makePaginatedResource(null, null, ['x'])); - } - - // -- IteratorAggregate -- - - public function testForeachIteratesDataItems() - { - $data = ['item1', 'item2', 'item3']; - $resource = $this->makePaginatedResource(null, null, $data); - - $collected = []; - foreach ($resource as $item) { - $collected[] = $item; - } - - $this->assertSame($data, $collected); - } - - public function testForeachOnEmptyData() - { - $resource = $this->makePaginatedResource(); - - $collected = []; - foreach ($resource as $item) { - $collected[] = $item; - } - - $this->assertSame([], $collected); - } - - // -- offsetGet edge cases -- - - public function testOffsetGetReturnsNullForUnknownOffset() - { - $resource = $this->makePaginatedResource(); - - $this->assertNull($resource[99]); - $this->assertNull($resource['unknown_key']); - } -} diff --git a/tests/WorkOS/PasswordlessTest.php b/tests/WorkOS/PasswordlessTest.php deleted file mode 100644 index dc1b2b04..00000000 --- a/tests/WorkOS/PasswordlessTest.php +++ /dev/null @@ -1,91 +0,0 @@ -traitSetUp(); - - $this->withApiKeyAndClientId(); - $this->passwordless = new Passwordless(); - } - - public function testCreateSession() - { - $path = "passwordless/sessions"; - $params = [ - "email" => "demo@foo-corp.com", - "type" => Resource\ConnectionType::MagicLink - ]; - - $result = $this->sessionResponseFixture(); - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $session = $this->passwordless->createSession("demo@foo-corp.com", null, null, Resource\ConnectionType::MagicLink, null, null); - $sessionFixture = $this->sessionFixture(); - - $this->assertSame($sessionFixture, $session->toArray()); - } - - public function testSendSession() - { - $sessionResponse = \json_decode($this->sessionResponseFixture(), true); - $session = Resource\PasswordlessSession::constructFromResponse($sessionResponse); - $path = "passwordless/sessions/$session->id/send"; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - null, - true - ); - - $this->assertTrue($this->passwordless->sendSession($session)); - } - - // Fixtures - - private function sessionResponseFixture() - { - return json_encode([ - "id" => "passwordless_session_abc123", - "email" => "demo@foo-corp.com", - "expires_at" => "2021-01-01T01:00:00.000Z", - "link" => "https://auth.workos.com/passwordless/alphanum123/confirm", - "object" => "passwordless_session" - ]); - } - - private function sessionFixture() - { - return [ - "id" => "passwordless_session_abc123", - "email" => "demo@foo-corp.com", - "expiresAt" => "2021-01-01T01:00:00.000Z", - "link" => "https://auth.workos.com/passwordless/alphanum123/confirm", - "object" => "passwordless_session" - ]; - } -} diff --git a/tests/WorkOS/PortalTest.php b/tests/WorkOS/PortalTest.php deleted file mode 100644 index e30bdb18..00000000 --- a/tests/WorkOS/PortalTest.php +++ /dev/null @@ -1,210 +0,0 @@ -traitSetUp(); - - $this->withApiKey(); - $this->ap = new Portal(); - } - - public function testGenerateLinkSSO() - { - $generateLinkPath = "portal/generate_link"; - - $result = $this->generatePortalLinkFixture(); - - $params = [ - "organization" => "org_01EHZNVPK3SFK441A1RGBFSHRT", - "intent" => "sso", - "return_url" => null, - "success_url" => null - ]; - - $this->mockRequest( - Client::METHOD_POST, - $generateLinkPath, - null, - $params, - true, - $result - ); - - $expectation = "https://id.workos.com/portal/launch?secret=secret"; - - $response = $this->ap->generateLink("org_01EHZNVPK3SFK441A1RGBFSHRT", "sso"); - $this->assertSame($expectation, $response->link); - } - - public function testGenerateLinkDSync() - { - $generateLinkPath = "portal/generate_link"; - - $result = $this->generatePortalLinkFixture(); - - $params = [ - "organization" => "org_01EHZNVPK3SFK441A1RGBFSHRT", - "intent" => "dsync", - "return_url" => null, - "success_url" => null - ]; - - $this->mockRequest( - Client::METHOD_POST, - $generateLinkPath, - null, - $params, - true, - $result - ); - - $expectation = "https://id.workos.com/portal/launch?secret=secret"; - - $response = $this->ap->generateLink("org_01EHZNVPK3SFK441A1RGBFSHRT", "dsync"); - $this->assertSame($expectation, $response->link); - } - - public function testGenerateLinkAuditLogs() - { - $generateLinkPath = "portal/generate_link"; - - $result = $this->generatePortalLinkFixture(); - - $params = [ - "organization" => "org_01EHZNVPK3SFK441A1RGBFSHRT", - "intent" => "audit_logs", - "return_url" => null, - "success_url" => null - ]; - - $this->mockRequest( - Client::METHOD_POST, - $generateLinkPath, - null, - $params, - true, - $result - ); - - $expectation = "https://id.workos.com/portal/launch?secret=secret"; - - $response = $this->ap->generateLink("org_01EHZNVPK3SFK441A1RGBFSHRT", "audit_logs"); - $this->assertSame($expectation, $response->link); - } - - public function testGenerateLinkLogStreams() - { - $generateLinkPath = "portal/generate_link"; - - $result = $this->generatePortalLinkFixture(); - - $params = [ - "organization" => "org_01EHZNVPK3SFK441A1RGBFSHRT", - "intent" => "log_streams", - "return_url" => null, - "success_url" => null - ]; - - $this->mockRequest( - Client::METHOD_POST, - $generateLinkPath, - null, - $params, - true, - $result - ); - - $expectation = "https://id.workos.com/portal/launch?secret=secret"; - - $response = $this->ap->generateLink("org_01EHZNVPK3SFK441A1RGBFSHRT", "log_streams"); - $this->assertSame($expectation, $response->link); - } - - public function testGenerateLinkCertificateRenewal() - { - $generateLinkPath = "portal/generate_link"; - - $result = $this->generatePortalLinkFixture(); - - $params = [ - "organization" => "org_01EHZNVPK3SFK441A1RGBFSHRT", - "intent" => "certificate_renewal", - "return_url" => null, - "success_url" => null - ]; - - $this->mockRequest( - Client::METHOD_POST, - $generateLinkPath, - null, - $params, - true, - $result - ); - - $expectation = "https://id.workos.com/portal/launch?secret=secret"; - - $response = $this->ap->generateLink("org_01EHZNVPK3SFK441A1RGBFSHRT", "certificate_renewal"); - $this->assertSame($expectation, $response->link); - } - - public function testGenerateLinkDomainVerification() - { - $generateLinkPath = "portal/generate_link"; - - $result = $this->generatePortalLinkFixture(); - - $params = [ - "organization" => "org_01EHZNVPK3SFK441A1RGBFSHRT", - "intent" => "domain_verification", - "return_url" => null, - "success_url" => null - ]; - - $this->mockRequest( - Client::METHOD_POST, - $generateLinkPath, - null, - $params, - true, - $result - ); - - $expectation = "https://id.workos.com/portal/launch?secret=secret"; - - $response = $this->ap->generateLink("org_01EHZNVPK3SFK441A1RGBFSHRT", "domain_verification"); - $this->assertSame($expectation, $response->link); - } - - public function testGenerateLinkWithInvalidIntent() - { - $this->expectException(Exception\UnexpectedValueException::class); - $this->expectExceptionMessage("Invalid intent. Valid values are:"); - - $this->ap->generateLink("org_01EHZNVPK3SFK441A1RGBFSHRT", "invalid_intent"); - } - - // Fixtures - - private function generatePortalLinkFixture() - { - return json_encode([ - "link" => "https://id.workos.com/portal/launch?secret=secret" - ]); - } -} diff --git a/tests/WorkOS/RBACTest.php b/tests/WorkOS/RBACTest.php deleted file mode 100644 index eccb3c48..00000000 --- a/tests/WorkOS/RBACTest.php +++ /dev/null @@ -1,618 +0,0 @@ -traitSetUp(); - - $this->withApiKey(); - $this->rbac = new RBAC(); - } - - public function testCreatePermission() - { - $path = "authorization/permissions"; - - $result = $this->permissionResponseFixture(); - - $params = [ - "slug" => "posts:read", - "name" => "Read Posts", - "description" => "Allows reading posts", - ]; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $permission = $this->permissionFixture(); - - $response = $this->rbac->createPermission("posts:read", "Read Posts", "Allows reading posts"); - $this->assertSame($permission, $response->toArray()); - } - - public function testListPermissions() - { - $path = "authorization/permissions"; - - $result = $this->permissionsListResponseFixture(); - - $params = [ - "limit" => RBAC::DEFAULT_PAGE_SIZE, - "before" => null, - "after" => null, - "order" => null, - ]; - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - $params, - true, - $result - ); - - $permission = $this->permissionFixture(); - - $response = $this->rbac->listPermissions(); - $this->assertSame($permission, $response->permissions[0]->toArray()); - } - - public function testGetPermission() - { - $path = "authorization/permissions/posts:read"; - - $result = $this->permissionResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - null, - true, - $result - ); - - $permission = $this->permissionFixture(); - - $response = $this->rbac->getPermission("posts:read"); - $this->assertSame($permission, $response->toArray()); - } - - public function testUpdatePermission() - { - $path = "authorization/permissions/posts:read"; - - $result = $this->permissionResponseFixture(); - - $params = [ - "name" => "Read Posts Updated", - ]; - - $this->mockRequest( - Client::METHOD_PATCH, - $path, - null, - $params, - true, - $result - ); - - $permission = $this->permissionFixture(); - - $response = $this->rbac->updatePermission("posts:read", "Read Posts Updated"); - $this->assertSame($permission, $response->toArray()); - } - - public function testDeletePermission() - { - $path = "authorization/permissions/posts:read"; - - $this->mockRequest( - Client::METHOD_DELETE, - $path, - null, - null, - true - ); - - $response = $this->rbac->deletePermission("posts:read"); - $this->assertSame([], $response); - } - - public function testCreateEnvironmentRole() - { - $path = "authorization/roles"; - - $result = $this->roleResponseFixture(); - - $params = [ - "slug" => "admin", - "name" => "Admin", - "description" => "Admin role", - ]; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $role = $this->roleFixture(); - - $response = $this->rbac->createEnvironmentRole("admin", "Admin", "Admin role"); - $this->assertSame($role, $response->toArray()); - } - - public function testListEnvironmentRoles() - { - $path = "authorization/roles"; - - $result = $this->rolesListResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - null, - true, - $result - ); - - $role = $this->roleFixture(); - - $roles = $this->rbac->listEnvironmentRoles(); - $this->assertSame($role, $roles[0]->toArray()); - } - - public function testGetEnvironmentRole() - { - $path = "authorization/roles/admin"; - - $result = $this->roleResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - null, - true, - $result - ); - - $role = $this->roleFixture(); - - $response = $this->rbac->getEnvironmentRole("admin"); - $this->assertSame($role, $response->toArray()); - } - - public function testUpdateEnvironmentRole() - { - $path = "authorization/roles/admin"; - - $result = $this->roleResponseFixture(); - - $params = [ - "name" => "Admin Updated", - ]; - - $this->mockRequest( - Client::METHOD_PATCH, - $path, - null, - $params, - true, - $result - ); - - $role = $this->roleFixture(); - - $response = $this->rbac->updateEnvironmentRole("admin", "Admin Updated"); - $this->assertSame($role, $response->toArray()); - } - - public function testSetEnvironmentRolePermissions() - { - $path = "authorization/roles/admin/permissions"; - - $result = $this->roleResponseFixture(); - - $params = [ - "permissions" => ["posts:read", "posts:write"], - ]; - - $this->mockRequest( - Client::METHOD_PUT, - $path, - null, - $params, - true, - $result - ); - - $role = $this->roleFixture(); - - $response = $this->rbac->setEnvironmentRolePermissions("admin", ["posts:read", "posts:write"]); - $this->assertSame($role, $response->toArray()); - } - - public function testAddEnvironmentRolePermission() - { - $path = "authorization/roles/admin/permissions"; - - $result = $this->roleResponseFixture(); - - $params = [ - "slug" => "posts:read", - ]; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $role = $this->roleFixture(); - - $response = $this->rbac->addEnvironmentRolePermission("admin", "posts:read"); - $this->assertSame($role, $response->toArray()); - } - - public function testCreateOrganizationRole() - { - $path = "authorization/organizations/org_01EHQMYV6MBK39QC5PZXHY59C3/roles"; - - $result = $this->organizationRoleResponseFixture(); - - $params = [ - "slug" => "org-admin", - "name" => "Org Admin", - "description" => "Organization admin role", - ]; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $role = $this->organizationRoleFixture(); - - $response = $this->rbac->createOrganizationRole("org_01EHQMYV6MBK39QC5PZXHY59C3", "org-admin", "Org Admin", "Organization admin role"); - $this->assertSame($role, $response->toArray()); - } - - public function testListOrganizationRoles() - { - $path = "authorization/organizations/org_01EHQMYV6MBK39QC5PZXHY59C3/roles"; - - $result = $this->organizationRolesListResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - null, - true, - $result - ); - - $role = $this->organizationRoleFixture(); - - $roles = $this->rbac->listOrganizationRoles("org_01EHQMYV6MBK39QC5PZXHY59C3"); - $this->assertSame($role, $roles[0]->toArray()); - } - - public function testGetOrganizationRole() - { - $path = "authorization/organizations/org_01EHQMYV6MBK39QC5PZXHY59C3/roles/org-admin"; - - $result = $this->organizationRoleResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - null, - true, - $result - ); - - $role = $this->organizationRoleFixture(); - - $response = $this->rbac->getOrganizationRole("org_01EHQMYV6MBK39QC5PZXHY59C3", "org-admin"); - $this->assertSame($role, $response->toArray()); - } - - public function testUpdateOrganizationRole() - { - $path = "authorization/organizations/org_01EHQMYV6MBK39QC5PZXHY59C3/roles/org-admin"; - - $result = $this->organizationRoleResponseFixture(); - - $params = [ - "name" => "Org Admin Updated", - ]; - - $this->mockRequest( - Client::METHOD_PATCH, - $path, - null, - $params, - true, - $result - ); - - $role = $this->organizationRoleFixture(); - - $response = $this->rbac->updateOrganizationRole("org_01EHQMYV6MBK39QC5PZXHY59C3", "org-admin", "Org Admin Updated"); - $this->assertSame($role, $response->toArray()); - } - - public function testDeleteOrganizationRole() - { - $path = "authorization/organizations/org_01EHQMYV6MBK39QC5PZXHY59C3/roles/org-admin"; - - $this->mockRequest( - Client::METHOD_DELETE, - $path, - null, - null, - true - ); - - $response = $this->rbac->deleteOrganizationRole("org_01EHQMYV6MBK39QC5PZXHY59C3", "org-admin"); - $this->assertSame([], $response); - } - - public function testSetOrganizationRolePermissions() - { - $path = "authorization/organizations/org_01EHQMYV6MBK39QC5PZXHY59C3/roles/org-admin/permissions"; - - $result = $this->organizationRoleResponseFixture(); - - $params = [ - "permissions" => ["posts:read", "posts:write"], - ]; - - $this->mockRequest( - Client::METHOD_PUT, - $path, - null, - $params, - true, - $result - ); - - $role = $this->organizationRoleFixture(); - - $response = $this->rbac->setOrganizationRolePermissions("org_01EHQMYV6MBK39QC5PZXHY59C3", "org-admin", ["posts:read", "posts:write"]); - $this->assertSame($role, $response->toArray()); - } - - public function testAddOrganizationRolePermission() - { - $path = "authorization/organizations/org_01EHQMYV6MBK39QC5PZXHY59C3/roles/org-admin/permissions"; - - $result = $this->organizationRoleResponseFixture(); - - $params = [ - "slug" => "posts:read", - ]; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $role = $this->organizationRoleFixture(); - - $response = $this->rbac->addOrganizationRolePermission("org_01EHQMYV6MBK39QC5PZXHY59C3", "org-admin", "posts:read"); - $this->assertSame($role, $response->toArray()); - } - - public function testRemoveOrganizationRolePermission() - { - $path = "authorization/organizations/org_01EHQMYV6MBK39QC5PZXHY59C3/roles/org-admin/permissions/posts:read"; - - $this->mockRequest( - Client::METHOD_DELETE, - $path, - null, - null, - true - ); - - $response = $this->rbac->removeOrganizationRolePermission("org_01EHQMYV6MBK39QC5PZXHY59C3", "org-admin", "posts:read"); - $this->assertSame([], $response); - } - - // Fixtures - - private function permissionResponseFixture() - { - return json_encode([ - "object" => "permission", - "id" => "perm_01EHQMYV6MBK39QC5PZXHY59C3", - "slug" => "posts:read", - "name" => "Read Posts", - "description" => "Allows reading posts", - "resource_type_slug" => "organization", - "system" => false, - "created_at" => "2024-01-01T00:00:00.000Z", - "updated_at" => "2024-01-01T00:00:00.000Z" - ]); - } - - private function permissionsListResponseFixture() - { - return json_encode([ - "object" => "list", - "data" => [ - [ - "object" => "permission", - "id" => "perm_01EHQMYV6MBK39QC5PZXHY59C3", - "slug" => "posts:read", - "name" => "Read Posts", - "description" => "Allows reading posts", - "resource_type_slug" => "organization", - "system" => false, - "created_at" => "2024-01-01T00:00:00.000Z", - "updated_at" => "2024-01-01T00:00:00.000Z" - ] - ], - "list_metadata" => [ - "before" => null, - "after" => null - ] - ]); - } - - private function permissionFixture() - { - return [ - "id" => "perm_01EHQMYV6MBK39QC5PZXHY59C3", - "slug" => "posts:read", - "name" => "Read Posts", - "description" => "Allows reading posts", - "resource_type_slug" => "organization", - "system" => false, - "created_at" => "2024-01-01T00:00:00.000Z", - "updated_at" => "2024-01-01T00:00:00.000Z" - ]; - } - - private function roleResponseFixture() - { - return json_encode([ - "object" => "role", - "id" => "role_01EHQMYV6MBK39QC5PZXHY59C2", - "name" => "Admin", - "slug" => "admin", - "description" => "Admin role", - "permissions" => ["posts:read", "posts:write"], - "resource_type_slug" => "organization", - "type" => "EnvironmentRole", - "created_at" => "2024-01-01T00:00:00.000Z", - "updated_at" => "2024-01-01T00:00:00.000Z" - ]); - } - - private function rolesListResponseFixture() - { - return json_encode([ - "object" => "list", - "data" => [ - [ - "object" => "role", - "id" => "role_01EHQMYV6MBK39QC5PZXHY59C2", - "name" => "Admin", - "slug" => "admin", - "description" => "Admin role", - "permissions" => ["posts:read", "posts:write"], - "resource_type_slug" => "organization", - "type" => "EnvironmentRole", - "created_at" => "2024-01-01T00:00:00.000Z", - "updated_at" => "2024-01-01T00:00:00.000Z" - ] - ] - ]); - } - - private function roleFixture() - { - return [ - "id" => "role_01EHQMYV6MBK39QC5PZXHY59C2", - "name" => "Admin", - "slug" => "admin", - "description" => "Admin role", - "permissions" => ["posts:read", "posts:write"], - "resource_type_slug" => "organization", - "type" => "EnvironmentRole", - "created_at" => "2024-01-01T00:00:00.000Z", - "updated_at" => "2024-01-01T00:00:00.000Z" - ]; - } - - private function organizationRoleResponseFixture() - { - return json_encode([ - "object" => "role", - "id" => "role_01EHQMYV6MBK39QC5PZXHY59C5", - "name" => "Org Admin", - "slug" => "org-admin", - "description" => "Organization admin role", - "permissions" => ["posts:read", "posts:write"], - "resource_type_slug" => "organization", - "type" => "OrganizationRole", - "created_at" => "2024-01-01T00:00:00.000Z", - "updated_at" => "2024-01-01T00:00:00.000Z" - ]); - } - - private function organizationRolesListResponseFixture() - { - return json_encode([ - "object" => "list", - "data" => [ - [ - "object" => "role", - "id" => "role_01EHQMYV6MBK39QC5PZXHY59C5", - "name" => "Org Admin", - "slug" => "org-admin", - "description" => "Organization admin role", - "permissions" => ["posts:read", "posts:write"], - "resource_type_slug" => "organization", - "type" => "OrganizationRole", - "created_at" => "2024-01-01T00:00:00.000Z", - "updated_at" => "2024-01-01T00:00:00.000Z" - ] - ] - ]); - } - - private function organizationRoleFixture() - { - return [ - "id" => "role_01EHQMYV6MBK39QC5PZXHY59C5", - "name" => "Org Admin", - "slug" => "org-admin", - "description" => "Organization admin role", - "permissions" => ["posts:read", "posts:write"], - "resource_type_slug" => "organization", - "type" => "OrganizationRole", - "created_at" => "2024-01-01T00:00:00.000Z", - "updated_at" => "2024-01-01T00:00:00.000Z" - ]; - } -} diff --git a/tests/WorkOS/Resource/WebhookResponseTest.php b/tests/WorkOS/Resource/WebhookResponseTest.php deleted file mode 100644 index 9bda1461..00000000 --- a/tests/WorkOS/Resource/WebhookResponseTest.php +++ /dev/null @@ -1,149 +0,0 @@ -traitSetUp(); - $this->withApiKey(); - - $this->secret = 'test_secret'; - $this->timestamp = time() * 1000; // milliseconds - } - - public function testCreateAllowResponse() - { - $response = WebhookResponse::create( - WebhookResponse::USER_REGISTRATION_ACTION, - $this->secret, - WebhookResponse::VERDICT_ALLOW - ); - - $array = $response->toArray(); - - $this->assertEquals(WebhookResponse::USER_REGISTRATION_ACTION, $array['object']); - $this->assertArrayHasKey('payload', $array); - $this->assertArrayHasKey('signature', $array); - $this->assertEquals(WebhookResponse::VERDICT_ALLOW, $array['payload']['verdict']); - $this->assertArrayHasKey('timestamp', $array['payload']); - $this->assertArrayNotHasKey('error_message', $array['payload']); - } - - public function testCreateDenyResponse() - { - $errorMessage = 'Registration denied due to risk assessment'; - $response = WebhookResponse::create( - WebhookResponse::USER_REGISTRATION_ACTION, - $this->secret, - WebhookResponse::VERDICT_DENY, - $errorMessage - ); - - $array = $response->toArray(); - - $this->assertEquals(WebhookResponse::USER_REGISTRATION_ACTION, $array['object']); - $this->assertArrayHasKey('payload', $array); - $this->assertArrayHasKey('signature', $array); - $this->assertEquals(WebhookResponse::VERDICT_DENY, $array['payload']['verdict']); - $this->assertEquals($errorMessage, $array['payload']['error_message']); - $this->assertArrayHasKey('timestamp', $array['payload']); - } - - public function testCreateAuthenticationResponse() - { - $response = WebhookResponse::create( - WebhookResponse::AUTHENTICATION_ACTION, - $this->secret, - WebhookResponse::VERDICT_ALLOW - ); - - $array = $response->toArray(); - - $this->assertEquals(WebhookResponse::AUTHENTICATION_ACTION, $array['object']); - $this->assertArrayHasKey('payload', $array); - $this->assertArrayHasKey('signature', $array); - } - - public function testCreateWithoutSecret() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Secret is required'); - - WebhookResponse::create( - WebhookResponse::USER_REGISTRATION_ACTION, - '', - WebhookResponse::VERDICT_ALLOW - ); - } - - public function testInvalidResponseType() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Invalid response type'); - - WebhookResponse::create( - 'invalid_type', - $this->secret, - WebhookResponse::VERDICT_ALLOW - ); - } - - public function testInvalidVerdict() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Invalid verdict'); - - WebhookResponse::create( - WebhookResponse::USER_REGISTRATION_ACTION, - $this->secret, - 'invalid_verdict' - ); - } - - public function testDenyWithoutErrorMessage() - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Error message is required when verdict is Deny'); - - WebhookResponse::create( - WebhookResponse::USER_REGISTRATION_ACTION, - $this->secret, - WebhookResponse::VERDICT_DENY - ); - } - - public function testToJson() - { - $response = WebhookResponse::create( - WebhookResponse::USER_REGISTRATION_ACTION, - $this->secret, - WebhookResponse::VERDICT_ALLOW - ); - - $json = $response->toJson(); - $decoded = json_decode($json, true); - - $this->assertIsString($json); - $this->assertIsArray($decoded); - $this->assertEquals(WebhookResponse::USER_REGISTRATION_ACTION, $decoded['object']); - } -} diff --git a/tests/WorkOS/SSOTest.php b/tests/WorkOS/SSOTest.php deleted file mode 100644 index 7c256639..00000000 --- a/tests/WorkOS/SSOTest.php +++ /dev/null @@ -1,421 +0,0 @@ -traitSetUp(); - - $this->withApiKeyAndClientId(); - $this->sso = new SSO(); - } - - /** - * @dataProvider authorizationUrlTestProvider - */ - public function testAuthorizationURLExpectedParams( - $domain, - $redirectUri, - $state, - $provider, - $connection, - $organization = null, - $domainHint = null, - $loginHint = null - ) { - $expectedParams = [ - "client_id" => WorkOS::getClientId(), - "response_type" => "code" - ]; - - if ($domain) { - $expectedParams["domain"] = $domain; - } - - if ($redirectUri) { - $expectedParams["redirect_uri"] = $redirectUri; - } - - if (null !== $state && !empty($state)) { - $expectedParams["state"] = \json_encode($state); - } - - if ($provider) { - $expectedParams["provider"] = $provider; - } - - if ($connection) { - $expectedParams["connection"] = $connection; - } - - if ($organization) { - $expectedParams["organization"] = $organization; - } - - if ($domainHint) { - $expectedParams["domain_hint"] = $domainHint; - } - - if ($loginHint) { - $expectedParams["login_hint"] = $loginHint; - } - - $authorizationUrl = $this->sso->getAuthorizationUrl( - $domain, - $redirectUri, - $state, - $provider, - $connection, - $organization, - $domainHint, - $loginHint - ); - $paramsString = \parse_url($authorizationUrl, \PHP_URL_QUERY); - \parse_str($paramsString, $paramsArray); - - $this->assertSame($expectedParams, $paramsArray); - } - - public function testGetProfileAndTokenReturnsProfileWithExpectedValues() - { - $code = 'code'; - $path = "sso/token"; - $params = [ - "client_id" => WorkOS::getClientId(), - "client_secret" => WorkOS::getApikey(), - "code" => $code, - "grant_type" => "authorization_code" - ]; - - $result = $this->profileAndTokenResponseFixture(); - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - false, - $result - ); - - $profileAndToken = $this->sso->getProfileAndToken('code'); - $profileFixture = $this->profileFixture(); - - $this->assertSame("01DMEK0J53CVMC32CK5SE0KZ8Q", $profileAndToken->accessToken); - $this->assertEquals($profileFixture, $profileAndToken->profile->toArray()); - } - - public function testGetConnection() - { - $connection = "connection_id"; - $connectionPath = "connections/{$connection}"; - - $result = $this->connectionResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $connectionPath, - null, - null, - true, - $result - ); - - $connection = $this->sso->getConnection($connection); - $connectionFixture = $this->connectionFixture(); - - $this->assertSame($connectionFixture, $connection->toArray()); - } - - public function testListConnections() - { - $connectionsPath = "connections"; - $params = [ - "limit" => SSO::DEFAULT_PAGE_SIZE, - "before" => null, - "after" => null, - "domain" => null, - "connection_type" => null, - "organization_id" => null, - "order" => null - ]; - - $result = $this->connectionsResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $connectionsPath, - null, - $params, - true, - $result - ); - - $connection = $this->connectionFixture(); - - list($before, $after, $connections) = $this->sso->listConnections(); - $this->assertSame($connection, $connections[0]->toArray()); - } - - public function testListConnectionsPaginatedResourceAccessPatterns() - { - $connectionsPath = "connections"; - $params = [ - "limit" => SSO::DEFAULT_PAGE_SIZE, - "before" => null, - "after" => null, - "domain" => null, - "connection_type" => null, - "organization_id" => null, - "order" => null - ]; - - $result = $this->connectionsResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $connectionsPath, - null, - $params, - true, - $result - ); - - // Test 1: Bare destructuring (indexed) - [$before1, $after1, $connections1] = $this->sso->listConnections(); - $this->assertNull($before1); - $this->assertNull($after1); - $this->assertIsArray($connections1); - $this->assertCount(1, $connections1); - - // Mock the request again for the next test - $this->mockRequest( - Client::METHOD_GET, - $connectionsPath, - null, - $params, - true, - $result - ); - - // Test 2: Named destructuring - ["before" => $before2, "after" => $after2, "connections" => $connections2] = $this->sso->listConnections(); - $this->assertNull($before2); - $this->assertNull($after2); - $this->assertIsArray($connections2); - $this->assertCount(1, $connections2); - - // Mock the request again for the next test - $this->mockRequest( - Client::METHOD_GET, - $connectionsPath, - null, - $params, - true, - $result - ); - - // Test 3: Fluent access - $response = $this->sso->listConnections(); - $this->assertNull($response->before); - $this->assertNull($response->after); - $this->assertIsArray($response->connections); - $this->assertCount(1, $response->connections); - - // Test 4: Generic data accessor - $this->assertIsArray($response->data); - $this->assertSame($response->connections, $response->data); - } - - public function testDeleteConnection() - { - $connection = "connection_id"; - $connectionPath = "connections/{$connection}"; - $responseCode = 204; - - $this->mockRequest( - Client::METHOD_DELETE, - $connectionPath, - null, - null, - true, - null, - null, - $responseCode - ); - - $response = $this->sso->deleteConnection($connection); - $this->assertSame(204, $responseCode); - } - - // Providers - - public static function authorizationUrlTestProvider() - { - return [ - [null, null, null, Resource\ConnectionType::GoogleOAuth, null], - [null, null, null, null, "connection_123"], - [null, null, null, null, null, "org_01FG7HGMY2CZZR2FWHTEE94VF0"], - [null, "https://papagenos.com/auth/callback", null, null, "connection_123", null, "foo.com", null], - [null, "https://papagenos.com/auth/callback", null, null, "connection_123", null, null, "foo@workos.com"], - ["papagenos.com", "https://papagenos.com/auth/callback", null, null, null], - ["papagenos.com", null, null, null, null], - ["papagenos.com", "https://papagenos.com/auth/callback", ["toppings" => "ham"], null, null] - ]; - } - - // Fixtures - - private function profileAndTokenResponseFixture() - { - return json_encode([ - "access_token" => "01DMEK0J53CVMC32CK5SE0KZ8Q", - "profile" => [ - "id" => "prof_hen", - "email" => "hen@papagenos.com", - "first_name" => "hen", - "last_name" => "cha", - "organization_id" => "org_01FG7HGMY2CZZR2FWHTEE94VF0", - "connection_id" => "conn_01EMH8WAK20T42N2NBMNBCYHAG", - "connection_type" => "GoogleOAuth", - "idp_id" => "randomalphanum", - "role" => [ - "slug" => "admin" - ], - "roles" => [ - [ - "slug" => "admin" - ] - ], - "groups" => array("Admins", "Developers"), - "custom_attributes" => array("license" => "professional"), - "raw_attributes" => array( - "email" => "hen@papagenos.com", - "first_name" => "hen", - "last_name" => "cha", - "ipd_id" => "randomalphanum", - "groups" => array("Admins", "Developers"), - "license" => "professional" - ) - ] - ]); - } - - private function profileFixture() - { - return [ - "id" => "prof_hen", - "email" => "hen@papagenos.com", - "firstName" => "hen", - "lastName" => "cha", - "organizationId" => "org_01FG7HGMY2CZZR2FWHTEE94VF0", - "connectionId" => "conn_01EMH8WAK20T42N2NBMNBCYHAG", - "connectionType" => "GoogleOAuth", - "idpId" => "randomalphanum", - "role" => new RoleResponse("admin"), - "roles" => [ - new RoleResponse("admin"), - ], - "groups" => array("Admins", "Developers"), - "customAttributes" => array("license" => "professional"), - "rawAttributes" => array( - "email" => "hen@papagenos.com", - "first_name" => "hen", - "last_name" => "cha", - "ipd_id" => "randomalphanum", - "groups" => array("Admins", "Developers"), - "license" => "professional" - ), - ]; - } - - private function connectionFixture() - { - return [ - "id" => "conn_01E0CG2C820RP4VS50PRJF8YPX", - "domains" => [ - [ - "id" => "conn_dom_01E2GCC7Q3KCNEFA2BW9MXR4T5", - "domain" => "workos.com" - ] - ], - "state" => "active", - "status" => "linked", - "name" => "Google OAuth 2.0", - "connectionType" => "GoogleOAuth", - "organizationId" => "org_1234", - ]; - } - - private function connectionResponseFixture() - { - return json_encode([ - "id" => "conn_01E0CG2C820RP4VS50PRJF8YPX", - "state" => "active", - "status" => "linked", - "name" => "Google OAuth 2.0", - "connection_type" => "GoogleOAuth", - "organization_id" => "org_1234", - "domains" => [ - [ - "object" => "connection_domain", - "id" => "conn_dom_01E2GCC7Q3KCNEFA2BW9MXR4T5", - "domain" => "workos.com" - ] - ] - ]); - } - - private function connectionsResponseFixture() - { - return json_encode([ - "data" => [ - [ - "id" => "conn_01E0CG2C820RP4VS50PRJF8YPX", - "domains" => [ - [ - "id" => "conn_dom_01E2GCC7Q3KCNEFA2BW9MXR4T5", - "domain" => "workos.com" - ] - ], - "state" => "active", - "status" => "linked", - "name" => "Google OAuth 2.0", - "connection_type" => "GoogleOAuth", - "oidc_client_id" => null, - "oidc_client_secret" => null, - "oidc_discovery_endpoint" => null, - "oidc_redirect_uri" => null, - "saml_entity_id" => null, - "saml_idp_url" => null, - "saml_relying_party_private_key" => null, - "saml_relying_party_public_key" => null, - "saml_x509_certs" => null, - "organization_id" => "org_1234", - "oauth_uid" => "oauthuid", - "oauth_secret" => "oauthsecret", - "oauth_redirect_uri" => "http://localhost:7000/sso/oauth/google/GbQX1B6LWUYcsGiq6k20iCUMA/callback", - ] - ], - "list_metadata" => [ - "before" => null, - "after" => null - ], - ]); - } -} diff --git a/tests/WorkOS/Session/HaliteSessionEncryptionTest.php b/tests/WorkOS/Session/HaliteSessionEncryptionTest.php deleted file mode 100644 index 540b9dfc..00000000 --- a/tests/WorkOS/Session/HaliteSessionEncryptionTest.php +++ /dev/null @@ -1,175 +0,0 @@ -encryptor = new HaliteSessionEncryption(); - } - - public function testSealAndUnseal() - { - $data = [ - 'access_token' => 'test_access_token_12345', - 'refresh_token' => 'test_refresh_token_67890', - 'session_id' => 'session_01H7X1M4TZJN5N4HG4XXMA1234' - ]; - - $sealed = $this->encryptor->seal($data, $this->password); - - $this->assertIsString($sealed); - $this->assertNotEmpty($sealed); - $this->assertGreaterThan(0, strlen($sealed)); - - $unsealed = $this->encryptor->unseal($sealed, $this->password); - - $this->assertEquals($data, $unsealed); - } - - public function testSealedDataIsDifferentEachTime() - { - $data = ['test' => 'value']; - - $sealed1 = $this->encryptor->seal($data, $this->password); - $sealed2 = $this->encryptor->seal($data, $this->password); - - // Encrypted data should be different each time due to random nonce - $this->assertNotEquals($sealed1, $sealed2); - - // But both should decrypt to the same value - $unsealed1 = $this->encryptor->unseal($sealed1, $this->password); - $unsealed2 = $this->encryptor->unseal($sealed2, $this->password); - - $this->assertEquals($data, $unsealed1); - $this->assertEquals($data, $unsealed2); - } - - public function testUnsealWithWrongPasswordFails() - { - $data = ['test' => 'value']; - $sealed = $this->encryptor->seal($data, $this->password); - - $this->expectException(UnexpectedValueException::class); - $this->expectExceptionMessage('Failed to unseal session'); - - $this->encryptor->unseal($sealed, 'wrong-password-that-should-not-work'); - } - - public function testExpiredSessionFails() - { - $data = ['test' => 'value']; - $sealed = $this->encryptor->seal($data, $this->password, -1); // Already expired (TTL of -1 second) - - $this->expectException(UnexpectedValueException::class); - $this->expectExceptionMessage('Session has expired'); - - $this->encryptor->unseal($sealed, $this->password); - } - - public function testCustomTTL() - { - $data = ['test' => 'value']; - $ttl = 3600; // 1 hour - - $sealed = $this->encryptor->seal($data, $this->password, $ttl); - $unsealed = $this->encryptor->unseal($sealed, $this->password); - - $this->assertEquals($data, $unsealed); - } - - public function testLongTTL() - { - $data = ['test' => 'value']; - $ttl = 2592000; // 30 days (WorkOS session default) - - $sealed = $this->encryptor->seal($data, $this->password, $ttl); - $unsealed = $this->encryptor->unseal($sealed, $this->password); - - $this->assertEquals($data, $unsealed); - } - - public function testComplexDataStructures() - { - $data = [ - 'access_token' => 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...', - 'refresh_token' => 'refresh_01H7X1M4TZJN5N4HG4XXMA1234', - 'session_id' => 'session_01H7X1M4TZJN5N4HG4XXMA1234', - 'user' => [ - 'id' => 'user_123', - 'email' => 'test@example.com', - 'first_name' => 'Test', - 'last_name' => 'User' - ], - 'organization_id' => 'org_123', - 'roles' => ['admin', 'user'], - 'permissions' => ['read', 'write', 'delete'] - ]; - - $sealed = $this->encryptor->seal($data, $this->password); - $unsealed = $this->encryptor->unseal($sealed, $this->password); - - $this->assertEquals($data, $unsealed); - } - - public function testInvalidBase64Fails() - { - $this->expectException(UnexpectedValueException::class); - $this->expectExceptionMessage('Failed to unseal session'); - - $this->encryptor->unseal('not-valid-base64-!@#$%^&*()', $this->password); - } - - public function testCorruptedDataFails() - { - $data = ['test' => 'value']; - $sealed = $this->encryptor->seal($data, $this->password); - - // Corrupt the sealed data by modifying a character - $corrupted = substr($sealed, 0, -5) . 'XXXXX'; - - $this->expectException(UnexpectedValueException::class); - - $this->encryptor->unseal($corrupted, $this->password); - } - - public function testEmptyDataArray() - { - $data = []; - - $sealed = $this->encryptor->seal($data, $this->password); - $unsealed = $this->encryptor->unseal($sealed, $this->password); - - $this->assertEquals($data, $unsealed); - } - - public function testDifferentPasswordsProduceDifferentResults() - { - $data = ['test' => 'value']; - $password1 = 'password-one-for-testing-encryption'; - $password2 = 'password-two-for-testing-encryption'; - - $sealed1 = $this->encryptor->seal($data, $password1); - $sealed2 = $this->encryptor->seal($data, $password2); - - $this->assertNotEquals($sealed1, $sealed2); - - // Each can only be unsealed with its own password - $unsealed1 = $this->encryptor->unseal($sealed1, $password1); - $this->assertEquals($data, $unsealed1); - - $unsealed2 = $this->encryptor->unseal($sealed2, $password2); - $this->assertEquals($data, $unsealed2); - - // Trying to unseal with the wrong password should fail - $this->expectException(UnexpectedValueException::class); - $this->encryptor->unseal($sealed1, $password2); - } -} diff --git a/tests/WorkOS/Session/SigningOnlySessionHandlerTest.php b/tests/WorkOS/Session/SigningOnlySessionHandlerTest.php deleted file mode 100644 index 0c377a60..00000000 --- a/tests/WorkOS/Session/SigningOnlySessionHandlerTest.php +++ /dev/null @@ -1,277 +0,0 @@ -handler = new SigningOnlySessionHandler(); - $this->requestClientMock = $this->createMock(\WorkOS\RequestClient\RequestClientInterface::class); - } - - public function testSealAndUnseal() - { - $data = [ - 'access_token' => 'test_access_token_12345', - 'refresh_token' => 'test_refresh_token_67890', - 'session_id' => 'session_01H7X1M4TZJN5N4HG4XXMA1234' - ]; - - $sealed = $this->handler->seal($data, $this->password); - - $this->assertIsString($sealed); - $this->assertNotEmpty($sealed); - - $unsealed = $this->handler->unseal($sealed, $this->password); - - $this->assertEquals($data, $unsealed); - } - - public function testSealedDataIsReadable() - { - $data = ['test' => 'value']; - - $sealed = $this->handler->seal($data, $this->password); - - // Signing-only data should be decodable (not encrypted) - $decoded = json_decode(base64_decode($sealed), true); - $this->assertIsArray($decoded); - $this->assertArrayHasKey('p', $decoded); // payload - $this->assertArrayHasKey('s', $decoded); // signature - - // Payload should be readable - $payloadJson = base64_decode($decoded['p']); - $payload = json_decode($payloadJson, true); - $this->assertIsArray($payload); - $this->assertArrayHasKey('d', $payload); // data - $this->assertEquals($data, $payload['d']); - } - - public function testUnsealWithWrongPasswordFails() - { - $data = ['test' => 'value']; - $sealed = $this->handler->seal($data, $this->password); - - $this->expectException(UnexpectedValueException::class); - $this->expectExceptionMessage('Invalid session signature'); - - $this->handler->unseal($sealed, 'wrong-password'); - } - - public function testExpiredSessionFails() - { - $data = ['test' => 'value']; - $sealed = $this->handler->seal($data, $this->password, -1); // Already expired - - $this->expectException(UnexpectedValueException::class); - $this->expectExceptionMessage('Session expired'); - - $this->handler->unseal($sealed, $this->password); - } - - public function testCustomTTL() - { - $data = ['test' => 'value']; - $ttl = 3600; // 1 hour - - $sealed = $this->handler->seal($data, $this->password, $ttl); - $unsealed = $this->handler->unseal($sealed, $this->password); - - $this->assertEquals($data, $unsealed); - } - - public function testTamperedDataFails() - { - $data = ['test' => 'value']; - $sealed = $this->handler->seal($data, $this->password); - - // Decode, modify, re-encode (without updating signature) - $decoded = json_decode(base64_decode($sealed), true); - $payloadJson = base64_decode($decoded['p']); - $payload = json_decode($payloadJson, true); - $payload['d'] = ['test' => 'tampered']; // Modify the data - $decoded['p'] = base64_encode(json_encode($payload)); - $tampered = base64_encode(json_encode($decoded)); - - $this->expectException(UnexpectedValueException::class); - $this->expectExceptionMessage('Invalid session signature'); - - $this->handler->unseal($tampered, $this->password); - } - - public function testInvalidFormatFails() - { - $this->expectException(UnexpectedValueException::class); - $this->expectExceptionMessage('Invalid signed session format'); - - $this->handler->unseal('not-valid-base64-data', $this->password); - } - - public function testMissingPayloadFieldFails() - { - $invalid = base64_encode(json_encode(['s' => 'signature-only'])); - - $this->expectException(UnexpectedValueException::class); - $this->expectExceptionMessage('Invalid signed session format'); - - $this->handler->unseal($invalid, $this->password); - } - - public function testMissingSignatureFieldFails() - { - $invalid = base64_encode(json_encode(['p' => 'payload-only'])); - - $this->expectException(UnexpectedValueException::class); - $this->expectExceptionMessage('Invalid signed session format'); - - $this->handler->unseal($invalid, $this->password); - } - - public function testInvalidPayloadStructureFails() - { - // Create valid signature but with invalid payload structure - $payload = ['invalid' => 'structure']; // Missing v, d, e fields - $payloadJson = json_encode($payload); - $signature = hash_hmac('sha256', $payloadJson, $this->password, true); - - $sealed = base64_encode(json_encode([ - 'p' => base64_encode($payloadJson), - 's' => base64_encode($signature), - ])); - - $this->expectException(UnexpectedValueException::class); - $this->expectExceptionMessage('Invalid payload structure'); - - $this->handler->unseal($sealed, $this->password); - } - - public function testVersionCheckFails() - { - // Create valid signature but with wrong version - $payload = [ - 'v' => 999, // Unsupported version - 'd' => ['test' => 'value'], - 'e' => time() + 3600, - ]; - $payloadJson = json_encode($payload); - $signature = hash_hmac('sha256', $payloadJson, $this->password, true); - - $sealed = base64_encode(json_encode([ - 'p' => base64_encode($payloadJson), - 's' => base64_encode($signature), - ])); - - $this->expectException(UnexpectedValueException::class); - $this->expectExceptionMessage('Unsupported session version'); - - $this->handler->unseal($sealed, $this->password); - } - - public function testComplexDataStructures() - { - $data = [ - 'access_token' => 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...', - 'refresh_token' => 'refresh_01H7X1M4TZJN5N4HG4XXMA1234', - 'session_id' => 'session_01H7X1M4TZJN5N4HG4XXMA1234', - 'user' => [ - 'id' => 'user_123', - 'email' => 'test@example.com', - 'first_name' => 'Test', - 'last_name' => 'User' - ], - 'organization_id' => 'org_123', - 'roles' => ['admin', 'user'], - 'permissions' => ['read', 'write', 'delete'] - ]; - - $sealed = $this->handler->seal($data, $this->password); - $unsealed = $this->handler->unseal($sealed, $this->password); - - $this->assertEquals($data, $unsealed); - } - - public function testDifferentPasswordsProduceDifferentSignatures() - { - $data = ['test' => 'value']; - $password1 = 'password-one-for-signing'; - $password2 = 'password-two-for-signing'; - - $sealed1 = $this->handler->seal($data, $password1); - $sealed2 = $this->handler->seal($data, $password2); - - // Signatures should be different - $this->assertNotEquals($sealed1, $sealed2); - - // Each can only be unsealed with its own password - $unsealed1 = $this->handler->unseal($sealed1, $password1); - $this->assertEquals($data, $unsealed1); - - $unsealed2 = $this->handler->unseal($sealed2, $password2); - $this->assertEquals($data, $unsealed2); - } - - public function testSignatureIsConstantTimeCompared() - { - // This test verifies hash_equals is used (timing attack prevention) - // We can't directly test timing, but we ensure the code path exists - $data = ['test' => 'value']; - $sealed = $this->handler->seal($data, $this->password); - - // Valid unseal should work - $unsealed = $this->handler->unseal($sealed, $this->password); - $this->assertEquals($data, $unsealed); - } - - public function testImplementsSessionEncryptionInterface() - { - $this->assertInstanceOf(SessionEncryptionInterface::class, $this->handler); - } - - public function testCanBeUsedWithUserManagement() - { - // Set up required configuration - WorkOS::setApiKey('sk_test_12345'); - - // Set up mock to throw HTTP exception on API call - $response = new Response('{"error": "server_error"}', [], 500); - Client::setRequestClient($this->requestClientMock); - $this->requestClientMock - ->expects($this->atLeastOnce()) - ->method('request') - ->willThrowException(new ServerException($response)); - - // SigningOnlySessionHandler can be injected into UserManagement - $userManagement = new \WorkOS\UserManagement($this->handler); - - $data = [ - 'access_token' => 'test_access_token', - 'refresh_token' => 'test_refresh_token', - ]; - - // Seal directly (as authkit-php would do) - $sealed = $this->handler->seal($data, $this->password); - - // UserManagement should be able to unseal it via authenticateWithSessionCookie - // (will get HTTP error since no API, but that's past the encryption layer) - $result = $userManagement->authenticateWithSessionCookie($sealed, $this->password); - - // Should succeed past encryption (get HTTP error, not encryption error) - $this->assertInstanceOf(\WorkOS\Resource\SessionAuthenticationFailureResponse::class, $result); - $this->assertEquals( - \WorkOS\Resource\SessionAuthenticationFailureResponse::REASON_HTTP_ERROR, - $result->reason - ); - } -} diff --git a/tests/WorkOS/UserManagementTest.php b/tests/WorkOS/UserManagementTest.php deleted file mode 100644 index cd8b74d8..00000000 --- a/tests/WorkOS/UserManagementTest.php +++ /dev/null @@ -1,2602 +0,0 @@ -traitSetUp(); - - $this->withApiKeyAndClientId(); - $this->userManagement = new UserManagement(); - } - - public function testDeleteUser() - { - $userId = "user_01H7X1M4TZJN5N4HG4XXMA1234"; - $path = "user_management/users/{$userId}"; - $responseCode = 200; - - $this->mockRequest( - Client::METHOD_DELETE, - $path, - null, - null, - true, - null, - null, - $responseCode - ); - - $response = $this->userManagement->deleteUser($userId); - $this->assertSame(200, $responseCode); - $this->assertSame($response, []); - } - - public function testUpdateUser() - { - $userId = "user_01H7X1M4TZJN5N4HG4XXMA1234"; - $path = "user_management/users/{$userId}"; - - $result = $this->createUserResponseFixture(); - - $params = [ - "first_name" => "Damien", - "last_name" => "Alabaster", - "email_verified" => true, - "password" => null, - "password_hash" => null, - "password_hash_type" => null, - "external_id" => null, - "metadata" => null, - "email" => null - ]; - - $this->mockRequest( - Client::METHOD_PUT, - $path, - null, - $params, - true, - $result - ); - - $user = $this->userFixture(); - - $response = $this->userManagement->updateUser("user_01H7X1M4TZJN5N4HG4XXMA1234", "Damien", "Alabaster", true); - $this->assertSame($user, $response->toArray()); - } - - public function testUpdateUserWithNullOptionalParams() - { - $userId = "user_01H7X1M4TZJN5N4HG4XXMA1234"; - $path = "user_management/users/{$userId}"; - - $result = $this->createUserResponseFixture(); - - $params = [ - "first_name" => null, - "last_name" => null, - "email_verified" => null, - "password" => null, - "password_hash" => null, - "password_hash_type" => null, - "external_id" => null, - "metadata" => null, - "email" => null - ]; - - $this->mockRequest( - Client::METHOD_PUT, - $path, - null, - $params, - true, - $result - ); - - $user = $this->userFixture(); - - $response = $this->userManagement->updateUser("user_01H7X1M4TZJN5N4HG4XXMA1234", null, null, null, null, null, null, null, null, null); - $this->assertSame($user, $response->toArray()); - } - - public function testAuthorizationURLInvalidInputs() - { - $this->expectException(Exception\UnexpectedValueException::class); - $authorizationUrl = $this->userManagement->getAuthorizationUrl( - "https://apage.com", - null, - "randomProvider", - null, - null, - null, - null, - 'sign-up' - ); - - $this->expectException(Exception\UnexpectedValueException::class); - $authorizationUrl = $this->userManagement->getAuthorizationUrl( - "https://apage.com", - null, - "randomProvider", - ); - - $this->expectException(Exception\UnexpectedValueException::class); - $authorizationUrl = $this->userManagement->getAuthorizationUrl( - "https://apage.com", - null, - null, - null, - ); - } - - public static function authorizationUrlTestDataProvider() - { - return [ - [null, null, Resource\ConnectionType::AppleOAuth, null], - [null, null, Resource\ConnectionType::GitHubOAuth, null], - [null, null, Resource\ConnectionType::GoogleOAuth, null], - [null, null, Resource\ConnectionType::MicrosoftOAuth, null], - [null, null, null, "connection_123"], - [null, null, null, null, "org_01FG7HGMY2CZZR2FWHTEE94VF0"], - ["https://papagenos.com/auth/callback", null, null, "connection_123", null, "foo.com", null], - ["https://papagenos.com/auth/callback", null, null, "connection_123", null, null, "foo@workos.com"], - ["https://papagenos.com/auth/callback", null, null, "connection_123"], - [null, null, null, "connection_123"], - ["https://papagenos.com/auth/callback", ["toppings" => "ham"], null, "connection_123"], - ["https://papagenos.com/auth/callback", null, null, "connection_123", null, null, null, null, ["read", "write"]], - [null, null, Resource\ConnectionType::GoogleOAuth, null, null, null, null, null, ["email", "profile"]] - ]; - } - - /** - * @dataProvider authorizationUrlTestDataProvider - */ - public function testAuthorizationURLExpectedParams( - $redirectUri, - $state, - $provider, - $connectionId, - $organizationId = null, - $domainHint = null, - $loginHint = null, - $screenHint = null, - $providerScopes = null - ) { - $expectedParams = [ - "client_id" => WorkOS::getClientId(), - "response_type" => "code" - ]; - - if ($redirectUri) { - $expectedParams["redirect_uri"] = $redirectUri; - } - - if (null !== $state && !empty($state)) { - $expectedParams["state"] = \json_encode($state); - } - - if ($provider) { - $expectedParams["provider"] = $provider; - } - - if ($connectionId) { - $expectedParams["connection_id"] = $connectionId; - } - - if ($organizationId) { - $expectedParams["organization_id"] = $organizationId; - } - - if ($domainHint) { - $expectedParams["domain_hint"] = $domainHint; - } - - if ($loginHint) { - $expectedParams["login_hint"] = $loginHint; - } - - if ($providerScopes && is_array($providerScopes)) { - $expectedParams["provider_scopes"] = implode(",", $providerScopes); - } - - $authorizationUrl = $this->userManagement->getAuthorizationUrl( - $redirectUri, - $state, - $provider, - $connectionId, - $organizationId, - $domainHint, - $loginHint, - $screenHint, - $providerScopes - ); - $paramsString = \parse_url($authorizationUrl, \PHP_URL_QUERY); - \parse_str($paramsString, $paramsArray); - $this->assertSame($expectedParams, $paramsArray); - } - - public function testAuthenticateWithPassword() - { - $path = "user_management/authenticate"; - WorkOS::setApiKey("sk_test_12345"); - $result = $this->UserResponseFixture(); - - $params = [ - "client_id" => "project_0123456", - "email" => "marcelina@foo-corp.com", - "password" => "i8uv6g34kd490s", - "ip_address" => null, - "user_agent" => null, - "grant_type" => "password", - "client_secret" => WorkOS::getApiKey() - ]; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $userFixture = $this->userFixture(); - - $response = $this->userManagement->authenticateWithPassword("project_0123456", "marcelina@foo-corp.com", "i8uv6g34kd490s"); - $this->assertSame($userFixture, $response->user->toArray()); - } - - public function testAuthenticateWithSelectedOrganization() - { - $path = "user_management/authenticate"; - WorkOS::setApiKey("sk_test_12345"); - $result = $this->userAndOrgResponseFixture(); - - $params = [ - "client_id" => "project_0123456", - "pending_authentication_token" => "token_super_safe", - "organization_id" => "org_01EHQMYV6MBK39QC5PZXHY59C3", - "ip_address" => null, - "user_agent" => null, - "grant_type" => "urn:workos:oauth:grant-type:organization-selection", - "client_secret" => WorkOS::getApiKey() - ]; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $userFixture = $this->userFixture(); - - $response = $this->userManagement->authenticateWithSelectedOrganization( - "project_0123456", - "token_super_safe", - "org_01EHQMYV6MBK39QC5PZXHY59C3" - ); - $this->assertSame($userFixture, $response->user->toArray()); - $this->assertSame("org_01EHQMYV6MBK39QC5PZXHY59C3", $response->organizationId); - } - - public function testAuthenticateWithEmailVerification() - { - $path = "user_management/authenticate"; - WorkOS::setApiKey("sk_test_12345"); - $result = $this->userAndOrgResponseFixture(); - - $params = [ - "client_id" => "project_0123456", - "code" => "code_super_safe", - "pending_authentication_token" => "token_super_safe", - "ip_address" => null, - "user_agent" => null, - "grant_type" => "urn:workos:oauth:grant-type:email-verification:code", - "client_secret" => WorkOS::getApiKey() - ]; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $userFixture = $this->userFixture(); - - $response = $this->userManagement->authenticateWithEmailVerification( - "project_0123456", - "code_super_safe", - "token_super_safe", - ); - $this->assertSame($userFixture, $response->user->toArray()); - } - - public function testAuthenticateWithCode() - { - $path = "user_management/authenticate"; - WorkOS::setApiKey("sk_test_12345"); - $result = $this->UserResponseFixture(); - - $params = [ - "client_id" => "project_0123456", - "code" => "01E2RJ4C05B52KKZ8FSRDAP23J", - "ip_address" => null, - "user_agent" => null, - "grant_type" => "authorization_code", - "client_secret" => WorkOS::getApiKey() - ]; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $userFixture = $this->userFixture(); - - $response = $this->userManagement->authenticateWithCode("project_0123456", "01E2RJ4C05B52KKZ8FSRDAP23J"); - $this->assertSame($userFixture, $response->user->toArray()); - } - - public function testAuthenticateImpersonatorWithCode() - { - $path = "user_management/authenticate"; - WorkOS::setApiKey("sk_test_12345"); - $result = $this->userAndImpersonatorResponseFixture(); - - $params = [ - "client_id" => "project_0123456", - "code" => "01E2RJ4C05B52KKZ8FSRDAP23J", - "ip_address" => null, - "user_agent" => null, - "grant_type" => "authorization_code", - "client_secret" => WorkOS::getApiKey() - ]; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $userFixture = $this->userFixture(); - - $response = $this->userManagement->authenticateWithCode("project_0123456", "01E2RJ4C05B52KKZ8FSRDAP23J"); - $this->assertSame($userFixture, $response->user->toArray()); - $this->assertSame([ - "email" => "admin@foocorp.com", - "reason" => "Helping debug an account issue." - ], $response->impersonator->toArray()); - } - - public function testAuthenticateWithOAuthTokensReturned() - { - $path = "user_management/authenticate"; - WorkOS::setApiKey("sk_test_12345"); - $result = $this->userAndOAuthTokensResponseFixture(); - - $params = [ - "client_id" => "project_0123456", - "code" => "01E2RJ4C05B52KKZ8FSRDAP23J", - "ip_address" => null, - "user_agent" => null, - "grant_type" => "authorization_code", - "client_secret" => WorkOS::getApiKey() - ]; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $userFixture = $this->userFixture(); - - $response = $this->userManagement->authenticateWithCode("project_0123456", "01E2RJ4C05B52KKZ8FSRDAP23J"); - $this->assertSame($userFixture, $response->user->toArray()); - - // Test OAuth tokens - $this->assertNotNull($response->oauthTokens); - $this->assertSame("oauth_access_token_123", $response->oauthTokens->accessToken); - $this->assertSame("oauth_refresh_token_456", $response->oauthTokens->refreshToken); - $this->assertSame(1640995200, $response->oauthTokens->expiresAt); - $this->assertSame(["read", "write"], $response->oauthTokens->scopes); - } - - public function testEnrollAuthFactor() - { - $userId = "user_123456"; - $path = "user_management/users/{$userId}/auth_factors"; - $params = [ - "type" => "totp", - "totp_user" => "totpUser", - "totp_issuer" => "totpIssuer" - ]; - - $result = $this->enrollAuthFactorResponseFixture(); - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $enrollFactorTotp = $this->userManagement->enrollAuthFactor($userId, "totp", "totpIssuer", "totpUser"); - $enrollUserAuthFactorFixture = $this->enrollAuthFactorFixture(); - $enrollUserAuthChallengeFixture = $this->enrollAuthChallengeFixture(); - - $this->assertSame($enrollUserAuthFactorFixture, $enrollFactorTotp->authenticationFactor->toArray()); - $this->assertSame($enrollUserAuthChallengeFixture, $enrollFactorTotp->authenticationChallenge->toArray()); - } - - public function testEnrollAuthFactorWithNullOptionalParams() - { - $userId = "user_123456"; - $path = "user_management/users/{$userId}/auth_factors"; - $params = [ - "type" => "totp", - "totp_user" => null, - "totp_issuer" => null - ]; - - $result = $this->enrollAuthFactorResponseFixture(); - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $enrollFactorTotp = $this->userManagement->enrollAuthFactor($userId, "totp", null, null); - $enrollUserAuthFactorFixture = $this->enrollAuthFactorFixture(); - $enrollUserAuthChallengeFixture = $this->enrollAuthChallengeFixture(); - - $this->assertSame($enrollUserAuthFactorFixture, $enrollFactorTotp->authenticationFactor->toArray()); - $this->assertSame($enrollUserAuthChallengeFixture, $enrollFactorTotp->authenticationChallenge->toArray()); - } - - public function testAuthenticateWithRefreshToken() - { - $path = "user_management/authenticate"; - WorkOS::setApiKey("sk_test_12345"); - $result = $this->UserResponseFixture(); - - $params = [ - "client_id" => "project_0123456", - "refresh_token" => "Xw0NsCVXMBf7svAoIoKBmkpEK", - "organization_id" => null, - "ip_address" => null, - "user_agent" => null, - "grant_type" => "refresh_token", - "client_secret" => WorkOS::getApiKey() - ]; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $userFixture = $this->userFixture(); - - $response = $this->userManagement->authenticateWithRefreshToken("project_0123456", "Xw0NsCVXMBf7svAoIoKBmkpEK"); - $this->assertSame($userFixture, $response->user->toArray()); - } - - public function testAuthenticateWithTotp() - { - $path = "user_management/authenticate"; - WorkOS::setApiKey("sk_test_12345"); - $result = $this->UserResponseFixture(); - - $params = [ - "client_id" => "project_0123456", - "pending_authentication_token" => "cTDQJTTkTkkVYxQUlKBIxEsFs", - "authentication_challenge_id" => "auth_challenge_01H96FETXGTW1QMBSBT2T36PW0", - "code" => "123456", - "ip_address" => null, - "user_agent" => null, - "grant_type" => "urn:workos:oauth:grant-type:mfa-totp", - "client_secret" => WorkOS::getApiKey() - ]; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $userFixture = $this->userFixture(); - - $response = $this->userManagement->authenticateWithTotp("project_0123456", "cTDQJTTkTkkVYxQUlKBIxEsFs", "auth_challenge_01H96FETXGTW1QMBSBT2T36PW0", "123456"); - $this->assertSame($userFixture, $response->user->toArray()); - } - - public function testAuthenticateWithMagicAuth() - { - $path = "user_management/authenticate"; - WorkOS::setApiKey("sk_test_12345"); - $result = $this->UserResponseFixture(); - - $params = [ - "client_id" => "project_0123456", - "code" => "123456", - "user_id" => "user_01H7X1M4TZJN5N4HG4XXMA1234", - "ip_address" => null, - "user_agent" => null, - "grant_type" => "urn:workos:oauth:grant-type:magic-auth:code", - "client_secret" => WorkOS::getApiKey() - ]; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $userFixture = $this->userFixture(); - - $response = $this->userManagement->authenticateWithMagicAuth("project_0123456", "123456", "user_01H7X1M4TZJN5N4HG4XXMA1234"); - $this->assertSame($userFixture, $response->user->toArray()); - } - - public function testCreateUser() - { - $path = "user_management/users"; - - $result = $this->createUserResponseFixture(); - - $params = [ - "email" => "test@test.com", - "password" => "x^T!V23UN1@V", - "first_name" => "Damien", - "last_name" => "Alabaster", - "email_verified" => true, - "password_hash" => null, - "password_hash_type" => null, - "external_id" => null, - "metadata" => null - ]; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $user = $this->userFixture(); - - $response = $this->userManagement->createUser("test@test.com", "x^T!V23UN1@V", "Damien", "Alabaster", true); - $this->assertSame($user, $response->toArray()); - } - - public function testCreateUserWithNullOptionalParams() - { - $path = "user_management/users"; - - $result = $this->createUserResponseFixture(); - - $params = [ - "email" => "test@test.com", - "password" => null, - "first_name" => null, - "last_name" => null, - "email_verified" => null, - "password_hash" => null, - "password_hash_type" => null, - "external_id" => null, - "metadata" => null - ]; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $user = $this->userFixture(); - - $response = $this->userManagement->createUser("test@test.com", null, null, null, null, null, null, null, null); - $this->assertSame($user, $response->toArray()); - } - - public function testGetEmailVerification() - { - $emailVerificationId = "email_verification_01E4ZCR3C56J083X43JQXF3JK5"; - $path = "user_management/email_verification/{$emailVerificationId}"; - - $result = $this->emailVerificationResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - null, - true, - $result - ); - - $response = $this->userManagement->getEmailVerification($emailVerificationId); - - $expected = $this->emailVerificationFixture(); - - $this->assertSame($response->toArray(), $expected); - } - - public function testSendVerificationEmail() - { - $userId = "user_01E4ZCR3C56J083X43JQXF3JK5"; - $path = "user_management/users/{$userId}/email_verification/send"; - - $result = $this->userResponseFixture(); - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - null, - true, - $result - ); - - - $user = $this->userFixture(); - - $response = $this->userManagement->sendVerificationEmail("user_01E4ZCR3C56J083X43JQXF3JK5"); - $this->assertSame($user, $response->user->toArray()); - } - - public function testVerifyEmail() - { - $userId = "user_01H7X1M4TZJN5N4HG4XXMA1234"; - $path = "user_management/users/{$userId}/email_verification/confirm"; - - $result = $this->UserResponseFixture(); - - $params = [ - "code" => "01DMEK0J53CVMC32CK5SE0KZ8Q", - ]; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $userFixture = $this->userFixture(); - - $response = $this->userManagement->verifyEmail("user_01H7X1M4TZJN5N4HG4XXMA1234", "01DMEK0J53CVMC32CK5SE0KZ8Q"); - $this->assertSame($userFixture, $response->user->toArray()); - } - - public function testGetPasswordReset() - { - $passwordResetId = "password_reset_01E4ZCR3C56J083X43JQXF3JK5"; - $path = "user_management/password_reset/{$passwordResetId}"; - - $result = $this->passwordResetResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - null, - true, - $result - ); - - $response = $this->userManagement->getPasswordReset($passwordResetId); - - $expected = $this->passwordResetFixture(); - - $this->assertSame($response->toArray(), $expected); - } - - public function testCreatePasswordReset() - { - $path = "user_management/password_reset"; - - $response = $this->passwordResetResponseFixture(); - - $params = [ - "email" => "someemail@test.com" - ]; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $response - ); - - $response = $this->userManagement->createPasswordReset( - "someemail@test.com", - ); - - $expected = $this->passwordResetFixture(); - $this->assertSame($expected, $response->toArray()); - } - - public function testSendPasswordResetEmail() - { - $path = "user_management/password_reset/send"; - - // Mock the API request - $responseCode = 200; - $params = [ - "email" => "test@test.com", - "password_reset_url" => "https://your-app.com/reset-password" - ]; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - null, - null, - $responseCode - ); - - $response = $this->userManagement->sendPasswordResetEmail("test@test.com", "https://your-app.com/reset-password"); - // Test the functionality - $this->assertSame(200, $responseCode); - $this->assertSame($response, []); - } - - public function testResetPassword() - { - $path = "user_management/password_reset/confirm"; - - $result = $this->userResponseFixture(); - - $params = [ - "token" => "01DMEK0J53CVMC32CK5SE0KZ8Q", - "new_password" => "^O9w8hiZu3x!" - ]; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $userFixture = $this->userFixture(); - - $response = $this->userManagement->resetPassword("01DMEK0J53CVMC32CK5SE0KZ8Q", "^O9w8hiZu3x!"); - $this->assertSame($userFixture, $response->user->toArray()); - } - - - - public function testGetUser() - { - $userId = "user_01H7X1M4TZJN5N4HG4XXMA1234"; - $path = "user_management/users/{$userId}"; - - $result = $this->getUserResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - null, - true, - $result - ); - - $user = $this->userFixture(); - - $response = $this->userManagement->getUser($userId); - - $this->assertSame($user, $response->toArray()); - } - - public function testListUsers() - { - $path = "user_management/users"; - $params = [ - "email" => null, - "organization_id" => null, - "limit" => UserManagement::DEFAULT_PAGE_SIZE, - "before" => null, - "after" => null, - "order" => null - ]; - - $result = $this->listUsersResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - $params, - true, - $result - ); - - $user = $this->userFixture(); - list($before, $after, $users) = $this->userManagement->listUsers(); - $this->assertSame($user, $users[0]->toArray()); - } - - public function testListUsersPaginatedResourceAccessPatterns() - { - $path = "user_management/users"; - $params = [ - "email" => null, - "organization_id" => null, - "limit" => UserManagement::DEFAULT_PAGE_SIZE, - "before" => null, - "after" => null, - "order" => null - ]; - - $result = $this->listUsersResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - $params, - true, - $result - ); - - // Test 1: Bare destructuring (indexed) - [$before1, $after1, $users1] = $this->userManagement->listUsers(); - $this->assertNull($before1); - $this->assertNull($after1); - $this->assertIsArray($users1); - $this->assertCount(1, $users1); - - // Mock the request again for the next test - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - $params, - true, - $result - ); - - // Test 2: Named destructuring - ["before" => $before2, "after" => $after2, "users" => $users2] = $this->userManagement->listUsers(); - $this->assertNull($before2); - $this->assertNull($after2); - $this->assertIsArray($users2); - $this->assertCount(1, $users2); - - // Mock the request again for the next test - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - $params, - true, - $result - ); - - // Test 3: Fluent access - $response = $this->userManagement->listUsers(); - $this->assertNull($response->before); - $this->assertNull($response->after); - $this->assertIsArray($response->users); - $this->assertCount(1, $response->users); - - // Test 4: Generic data accessor - $this->assertIsArray($response->data); - $this->assertSame($response->users, $response->data); - } - - public function testGetMagicAuth() - { - $magicAuthId = "magic_auth_01E4ZCR3C56J083X43JQXF3JK5"; - $path = "user_management/magic_auth/{$magicAuthId}"; - - $result = $this->magicAuthResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - null, - true, - $result - ); - - $response = $this->userManagement->getMagicAuth($magicAuthId); - - $expected = $this->magicAuthFixture(); - - $this->assertSame($response->toArray(), $expected); - } - - public function testCreateMagicAuth() - { - $path = "user_management/magic_auth"; - - $result = $this->magicAuthResponseFixture(); - - $params = [ - "email" => "someemail@test.com", - "invitation_token" => null - ]; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $response = $this->userManagement->createMagicAuth( - "someemail@test.com", - ); - - $expected = $this->magicAuthFixture(); - - $this->assertSame($response->toArray(), $expected); - } - - private function testSendMagicAuthCode() - { - $path = "user_management/magic_auth/send"; - - $params = [ - "email" => "test@test.com" - ]; - - $responseCode = 200; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - null, - null, - $responseCode - ); - - $user = $this->userFixture(); - - $response = $this->userManagement->sendMagicAuthCode("test@test.com"); - - $this->assertSame(200, $responseCode); - $this->assertSame($response, []); - } - - public function testListAuthFactors() - { - $userId = "user_01H96FETWYSJMJEGF0Q3ZB272F"; - $path = "user_management/users/{$userId}/auth_factors"; - - $result = $this->listAuthFactorResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - null, - true, - $result - ); - - $authFactors = $this->listAuthFactorFixture(); - $response = $this->userManagement->listAuthFactors("user_01H96FETWYSJMJEGF0Q3ZB272F"); - $this->assertSame($authFactors, $response[0]->toArray()); - } - - public function testCreateOrganizationMembership() - { - $userId = "user_01H7X1M4TZJN5N4HG4XXMA1234"; - $orgId = "org_01EHQMYV6MBK39QC5PZXHY59C3"; - $roleSlug = "admin"; - $path = "user_management/organization_memberships"; - - $result = $this->organizationMembershipResponseFixture(); - - $params = [ - "organization_id" => $orgId, - "user_id" => $userId, - "role_slug" => $roleSlug, - ]; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $organizationMembership = $this->organizationMembershipFixture(); - - $response = $this->userManagement->createOrganizationMembership($userId, $orgId, $roleSlug); - - $this->assertEquals($organizationMembership, $response->toArray()); - } - - public function testCreateOrganizationMembershipWithRoleSlugs() - { - $userId = "user_01H7X1M4TZJN5N4HG4XXMA1234"; - $orgId = "org_01EHQMYV6MBK39QC5PZXHY59C3"; - $roleSlugs = ["admin"]; - $path = "user_management/organization_memberships"; - - $result = $this->organizationMembershipResponseFixture(); - - $params = [ - "organization_id" => $orgId, - "user_id" => $userId, - "role_slugs" => $roleSlugs, - ]; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $organizationMembership = $this->organizationMembershipFixture(); - - $response = $this->userManagement->createOrganizationMembership($userId, $orgId, null, $roleSlugs); - - $this->assertEquals($organizationMembership, $response->toArray()); - } - - public function testCreateOrganizationMembershipWithNullRoleParams() - { - $userId = "user_01H7X1M4TZJN5N4HG4XXMA1234"; - $orgId = "org_01EHQMYV6MBK39QC5PZXHY59C3"; - $path = "user_management/organization_memberships"; - - $result = $this->organizationMembershipResponseFixture(); - - // When both roleSlug and roleSlugs are null, neither should be in params - $params = [ - "organization_id" => $orgId, - "user_id" => $userId, - ]; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $organizationMembership = $this->organizationMembershipFixture(); - - $response = $this->userManagement->createOrganizationMembership($userId, $orgId, null, null); - $this->assertEquals($organizationMembership, $response->toArray()); - } - - public function testGetOrganizationMembership() - { - $organizationMembershipId = "om_01E4ZCR3C56J083X43JQXF3JK5"; - $path = "user_management/organization_memberships/{$organizationMembershipId}"; - - $result = $this->organizationMembershipResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - null, - true, - $result - ); - - $organizationMembership = $this->organizationMembershipFixture(); - - $response = $this->userManagement->getOrganizationMembership($organizationMembershipId); - - $this->assertEquals($organizationMembership, $response->toArray()); - } - - public function testListOrganizationMemberships() - { - $userId = "user_01H7X1M4TZJN5N4HG4XXMA1234"; - $orgId = "org_01EHQMYV6MBK39QC5PZXHY59C3"; - $path = "user_management/organization_memberships"; - - $result = $this->organizationMembershipListResponseFixture(); - - $params = [ - "organization_id" => $orgId, - "user_id" => $userId, - "statuses" => null, - "limit" => 10, - "before" => null, - "after" => null, - "order" => null, - ]; - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - $params, - true, - $result - ); - - $organizationMembership = $this->organizationMembershipFixture(); - - list($before, $after, $organizationMemberships) = $this->userManagement->listOrganizationMemberships($userId, $orgId); - - $this->assertEquals($organizationMembership, $organizationMemberships[0]->toArray()); - } - - public function testListOrganizationMembershipsWithStatuses() - { - $userId = "user_01H7X1M4TZJN5N4HG4XXMA1234"; - $orgId = "org_01EHQMYV6MBK39QC5PZXHY59C3"; - $statuses = array("active", "inactive"); - $path = "user_management/organization_memberships"; - - $result = $this->organizationMembershipListResponseFixture(); - - $params = [ - "organization_id" => $orgId, - "user_id" => $userId, - "statuses" => "active,inactive", - "limit" => 10, - "before" => null, - "after" => null, - "order" => null, - ]; - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - $params, - true, - $result - ); - - $organizationMembership = $this->organizationMembershipFixture(); - - list($before, $after, $organizationMemberships) = $this->userManagement->listOrganizationMemberships($userId, $orgId, $statuses); - - $this->assertEquals($organizationMembership, $organizationMemberships[0]->toArray()); - } - - public function testListOrganizationMembershipsWithStatus() - { - $userId = "user_01H7X1M4TZJN5N4HG4XXMA1234"; - $orgId = "org_01EHQMYV6MBK39QC5PZXHY59C3"; - $statuses = array("inactive"); - $path = "user_management/organization_memberships"; - - $result = $this->organizationMembershipListResponseFixture(); - - $params = [ - "organization_id" => $orgId, - "user_id" => $userId, - "statuses" => "inactive", - "limit" => 10, - "before" => null, - "after" => null, - "order" => null, - ]; - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - $params, - true, - $result - ); - - $organizationMembership = $this->organizationMembershipFixture(); - - list($before, $after, $organizationMemberships) = $this->userManagement->listOrganizationMemberships($userId, $orgId, $statuses); - - $this->assertEquals($organizationMembership, $organizationMemberships[0]->toArray()); - } - - public function testDeleteOrganizationMembership() - { - $organizationMembershipId = "om_01E4ZCR3C56J083X43JQXF3JK5"; - $path = "user_management/organization_memberships/{$organizationMembershipId}"; - - $result = $this->organizationMembershipResponseFixture(); - - $this->mockRequest( - Client::METHOD_DELETE, - $path, - null, - null, - true, - ); - - $response = $this->userManagement->deleteOrganizationMembership($organizationMembershipId); - - $this->assertSame($response, []); - } - - public function testUpdateOrganizationMembership() - { - $organizationMembershipId = "om_01E4ZCR3C56J083X43JQXF3JK5"; - $roleSlug = "staff"; - $path = "user_management/organization_memberships/{$organizationMembershipId}"; - - $result = $this->organizationMembershipResponseFixture(); - - $this->mockRequest( - Client::METHOD_PUT, - $path, - null, - ["role_slug" => $roleSlug], - true, - $result - ); - - $response = $this->userManagement->updateOrganizationMembership($organizationMembershipId, $roleSlug); - $this->assertEquals($this->organizationMembershipFixture(), $response->toArray()); - } - - public function testUpdateOrganizationMembershipWithRoleSlugs() - { - $organizationMembershipId = "om_01E4ZCR3C56J083X43JQXF3JK5"; - $roleSlugs = ["admin"]; - $path = "user_management/organization_memberships/{$organizationMembershipId}"; - - $result = $this->organizationMembershipResponseFixture(); - - $this->mockRequest( - Client::METHOD_PUT, - $path, - null, - ["role_slugs" => $roleSlugs], - true, - $result - ); - - $response = $this->userManagement->updateOrganizationMembership($organizationMembershipId, null, $roleSlugs); - $this->assertEquals($this->organizationMembershipFixture(), $response->toArray()); - } - - public function testUpdateOrganizationMembershipWithNullRoleParams() - { - $organizationMembershipId = "om_01E4ZCR3C56J083X43JQXF3JK5"; - $path = "user_management/organization_memberships/{$organizationMembershipId}"; - - $result = $this->organizationMembershipResponseFixture(); - - // When both roleSlug and roleSlugs are null, params should be empty array - $this->mockRequest( - Client::METHOD_PUT, - $path, - null, - [], - true, - $result - ); - - $response = $this->userManagement->updateOrganizationMembership($organizationMembershipId, null, null); - $this->assertEquals($this->organizationMembershipFixture(), $response->toArray()); - } - - public function testDeactivateOrganizationMembership() - { - $organizationMembershipId = "om_01E4ZCR3C56J083X43JQXF3JK5"; - $path = "user_management/organization_memberships/{$organizationMembershipId}/deactivate"; - - $result = $this->organizationMembershipResponseFixture("inactive"); - - $this->mockRequest( - Client::METHOD_PUT, - $path, - null, - null, - true, - $result - ); - - $organizationMembership = $this->organizationMembershipFixture(); - - $response = $this->userManagement->deactivateOrganizationMembership($organizationMembershipId); - - $this->assertEquals(array_merge($organizationMembership, array("status" => "inactive")), $response->toArray()); - } - - public function testReactivateOrganizationMembership() - { - $organizationMembershipId = "om_01E4ZCR3C56J083X43JQXF3JK5"; - $path = "user_management/organization_memberships/{$organizationMembershipId}/reactivate"; - - $result = $this->organizationMembershipResponseFixture(); - - $this->mockRequest( - Client::METHOD_PUT, - $path, - null, - null, - true, - $result - ); - - $organizationMembership = $this->organizationMembershipFixture(); - - $response = $this->userManagement->reactivateOrganizationMembership($organizationMembershipId); - - $this->assertEquals($organizationMembership, $response->toArray()); - } - - public function testSendInvitation() - { - $path = "user_management/invitations"; - - $result = $this->invitationResponseFixture(); - - $params = [ - "email" => "someemail@test.com", - "organization_id" => "org_01EHQMYV6MBK39QC5PZXHY59C3", - "expires_in_days" => 10, - "inviter_user_id" => "user_01H7X1M4TZJN5N4HG4XXMA1234", - "role_slug" => "staff" - ]; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $response = $this->userManagement->sendInvitation( - "someemail@test.com", - "org_01EHQMYV6MBK39QC5PZXHY59C3", - 10, - "user_01H7X1M4TZJN5N4HG4XXMA1234", - "staff" - ); - - $expected = $this->invitationFixture(); - - $this->assertSame($response->toArray(), $expected); - } - - public function testSendInvitationWithNullOptionalParams() - { - $path = "user_management/invitations"; - - $result = $this->invitationResponseFixture(); - - // The implementation includes null values in params - $params = [ - "email" => "someemail@test.com", - "organization_id" => null, - "expires_in_days" => null, - "inviter_user_id" => null, - "role_slug" => null - ]; - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - $params, - true, - $result - ); - - $response = $this->userManagement->sendInvitation( - "someemail@test.com", - null, - null, - null, - null - ); - - $expected = $this->invitationFixture(); - - $this->assertSame($response->toArray(), $expected); - } - - public function testGetInvitation() - { - $invitationId = "invitation_01E4ZCR3C56J083X43JQXF3JK5"; - $path = "user_management/invitations/{$invitationId}"; - - $result = $this->invitationResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - null, - true, - $result - ); - - $response = $this->userManagement->getInvitation($invitationId); - - $expected = $this->invitationFixture(); - - $this->assertSame($response->toArray(), $expected); - } - - public function testFindInvitationByToken() - { - $invitationToken = "Z1uX3RbwcIl5fIGJJJCXXisdI"; - $path = "user_management/invitations/by_token/{$invitationToken}"; - - $result = $this->invitationResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - null, - true, - $result - ); - - $response = $this->userManagement->findInvitationByToken($invitationToken); - - $expected = $this->invitationFixture(); - - $this->assertSame($response->toArray(), $expected); - } - - public function testListInvitations() - { - $path = "user_management/invitations"; - - $result = $this->invitationListResponseFixture(); - - $params = [ - "email" => "someemail@test.com", - "organization_id" => null, - "limit" => 10, - "before" => null, - "after" => null, - "order" => null - ]; - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - $params, - true, - $result - ); - - list($before, $after, $invitations) = $this->userManagement->listInvitations("someemail@test.com"); - - $expected = $this->invitationFixture(); - - $this->assertSame($expected, $invitations[0]->toArray()); - } - - public function testRevokeInvitation() - { - $invitationId = "invitation_01E4ZCR3C56J083X43JQXF3JK5"; - $path = "user_management/invitations/{$invitationId}/revoke"; - - $result = $this->invitationResponseFixture(); - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - null, - true, - $result - ); - - $response = $this->userManagement->revokeInvitation($invitationId); - - $expected = $this->invitationFixture(); - - $this->assertSame($response->toArray(), $expected); - } - - public function testResendInvitation() - { - $invitationId = "invitation_01E4ZCR3C56J083X43JQXF3JK5"; - $path = "user_management/invitations/{$invitationId}/resend"; - - $result = $this->invitationResponseFixture(); - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - null, - true, - $result - ); - - $response = $this->userManagement->resendInvitation($invitationId); - - $expected = $this->invitationFixture(); - - $this->assertSame($response->toArray(), $expected); - } - - public function testResendInvitation404() - { - $invitationId = "invitation_01E4ZCR3C56J083X43JQXF3JK5"; - $path = "user_management/invitations/{$invitationId}/resend"; - - $this->expectException(Exception\NotFoundException::class); - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - null, - true, - null, - null, - 404 - ); - - $this->userManagement->resendInvitation($invitationId); - } - - public function testResendInvitationExpired() - { - $invitationId = "invitation_01E4ZCR3C56J083X43JQXF3JK5"; - $path = "user_management/invitations/{$invitationId}/resend"; - - $this->expectException(Exception\BadRequestException::class); - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - null, - true, - null, - null, - 400 - ); - - $this->userManagement->resendInvitation($invitationId); - } - - public function testResendInvitationRevoked() - { - $invitationId = "invitation_01E4ZCR3C56J083X43JQXF3JK5"; - $path = "user_management/invitations/{$invitationId}/resend"; - - $this->expectException(Exception\BadRequestException::class); - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - null, - true, - null, - null, - 400 - ); - - $this->userManagement->resendInvitation($invitationId); - } - - public function testResendInvitationAccepted() - { - $invitationId = "invitation_01E4ZCR3C56J083X43JQXF3JK5"; - $path = "user_management/invitations/{$invitationId}/resend"; - - $this->expectException(Exception\BadRequestException::class); - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - null, - true, - null, - null, - 400 - ); - - $this->userManagement->resendInvitation($invitationId); - } - - public function testAcceptInvitation() - { - $invitationId = "invitation_01E4ZCR3C56J083X43JQXF3JK5"; - $path = "user_management/invitations/{$invitationId}/accept"; - - $result = $this->invitationResponseFixture(); - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - null, - true, - $result - ); - - $response = $this->userManagement->acceptInvitation($invitationId); - - $expected = $this->invitationFixture(); - - $this->assertSame($response->toArray(), $expected); - } - - public function testAcceptInvitation404() - { - $invitationId = "invitation_01E4ZCR3C56J083X43JQXF3JK5"; - $path = "user_management/invitations/{$invitationId}/accept"; - - $this->expectException(Exception\NotFoundException::class); - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - null, - true, - null, - null, - 404 - ); - - $this->userManagement->acceptInvitation($invitationId); - } - - public function testGetJwksUrl() - { - $clientId = "12345"; - - $result = $this->userManagement->getJwksUrl($clientId); - - $baseUrl = WorkOS::getApiBaseUrl(); - $expected = "{$baseUrl}sso/jwks/{$clientId}"; - - $this->assertSame($result, $expected); - } - - public function testGetJwksUrlException() - { - $result = "clientId must not be empty"; - - try { - $this->userManagement->getJwksUrl(''); - } catch (Exception\UnexpectedValueException $e) { - $this->assertEquals($e->getMessage(), $result); - } - } - - public function testGetLogoutUrl() - { - $sessionId = "session_123"; - - $result = $this->userManagement->getLogoutUrl($sessionId); - - $baseUrl = WorkOS::getApiBaseUrl(); - $expected = "{$baseUrl}user_management/sessions/logout?session_id={$sessionId}"; - - $this->assertSame($result, $expected); - } - - public function testGetLogoutUrlWithReturnTo() - { - $result = $this->userManagement->getLogoutUrl("session_123", "https://your-app.com"); - - $this->assertSame( - $result, - "https://api.workos.com/user_management/sessions/logout?session_id=session_123&return_to=https%3A%2F%2Fyour-app.com" - ); - } - - public function testGetLogoutUrlException() - { - $result = "sessionId must not be empty"; - - try { - $this->userManagement->getLogoutUrl(''); - } catch (Exception\UnexpectedValueException $e) { - $this->assertEquals($e->getMessage(), $result); - } - } - - //Fixtures - - private function invitationResponseFixture() - { - return json_encode([ - "object" => "invitation", - "id" => "invitation_01E4ZCR3C56J083X43JQXF3JK5", - "email" => "someemail@test.com", - "state" => "pending", - "accepted_at" => "2021-07-01T19:07:33.155Z", - "revoked_at" => "2021-07-01T19:07:33.155Z", - "expires_at" => "2021-07-01T19:07:33.155Z", - "token" => "Z1uX3RbwcIl5fIGJJJCXXisdI", - "accept_invitation_url" => "https://your-app.com/invite?invitation_token=Z1uX3RbwcIl5fIGJJJCXXisdI", - "organization_id" => "org_01EHQMYV6MBK39QC5PZXHY59C3", - "inviter_user_id" => "user_01HYKE1DMN34HMHC180HJMF4AQ", - "created_at" => "2021-07-01T19:07:33.155Z", - "updated_at" => "2021-07-01T19:07:33.155Z", - ]); - } - - private function invitationFixture() - { - return [ - "object" => "invitation", - "id" => "invitation_01E4ZCR3C56J083X43JQXF3JK5", - "email" => "someemail@test.com", - "state" => "pending", - "acceptedAt" => "2021-07-01T19:07:33.155Z", - "revokedAt" => "2021-07-01T19:07:33.155Z", - "expiresAt" => "2021-07-01T19:07:33.155Z", - "token" => "Z1uX3RbwcIl5fIGJJJCXXisdI", - "acceptInvitationUrl" => "https://your-app.com/invite?invitation_token=Z1uX3RbwcIl5fIGJJJCXXisdI", - "organizationId" => "org_01EHQMYV6MBK39QC5PZXHY59C3", - "inviterUserId" => "user_01HYKE1DMN34HMHC180HJMF4AQ", - "createdAt" => "2021-07-01T19:07:33.155Z", - "updatedAt" => "2021-07-01T19:07:33.155Z", - ]; - } - - private function invitationListResponseFixture() - { - return json_encode( - [ - "data" => [ - [ - "object" => "invitation", - "id" => "invitation_01E4ZCR3C56J083X43JQXF3JK5", - "email" => "someemail@test.com", - "state" => "pending", - "accepted_at" => "2021-07-01T19:07:33.155Z", - "revoked_at" => "2021-07-01T19:07:33.155Z", - "expires_at" => "2021-07-01T19:07:33.155Z", - "token" => "Z1uX3RbwcIl5fIGJJJCXXisdI", - "accept_invitation_url" => "https://your-app.com/invite?invitation_token=Z1uX3RbwcIl5fIGJJJCXXisdI", - "organization_id" => "org_01EHQMYV6MBK39QC5PZXHY59C3", - "inviter_user_id" => "user_01HYKE1DMN34HMHC180HJMF4AQ", - "created_at" => "2021-07-01T19:07:33.155Z", - "updated_at" => "2021-07-01T19:07:33.155Z", - ] - ], - "list_metadata" => [ - "before" => null, - "after" => null - ], - ] - ); - } - - private function organizationMembershipResponseFixture($status = "active") - { - return json_encode([ - "object" => "organization_membership", - "id" => "om_01E4ZCR3C56J083X43JQXF3JK5", - "user_id" => "user_01H7X1M4TZJN5N4HG4XXMA1234", - "organization_id" => "org_01EHQMYV6MBK39QC5PZXHY59C3", - "role" => [ - "slug" => "admin", - ], - "roles" => [ - [ - "slug" => "admin", - ], - ], - "status" => $status, - "custom_attributes" => [], - "directory_managed" => false, - "created_at" => "2021-06-25T19:07:33.155Z", - "updated_at" => "2021-06-25T19:07:33.155Z", - ]); - } - - private function organizationMembershipListResponseFixture() - { - return json_encode( - [ - "data" => [ - [ - "object" => "organization_membership", - "id" => "om_01E4ZCR3C56J083X43JQXF3JK5", - "user_id" => "user_01H7X1M4TZJN5N4HG4XXMA1234", - "organization_id" => "org_01EHQMYV6MBK39QC5PZXHY59C3", - "role" => [ - "slug" => "admin", - ], - "roles" => [ - [ - "slug" => "admin", - ] - ], - "status" => "active", - "custom_attributes" => [], - "directory_managed" => false, - "created_at" => "2021-06-25T19:07:33.155Z", - "updated_at" => "2021-06-25T19:07:33.155Z", - ] - ], - "list_metadata" => [ - "before" => null, - "after" => null - ], - ] - ); - } - - private function organizationMembershipFixture() - { - return [ - "object" => "organization_membership", - "id" => "om_01E4ZCR3C56J083X43JQXF3JK5", - "userId" => "user_01H7X1M4TZJN5N4HG4XXMA1234", - "organizationId" => "org_01EHQMYV6MBK39QC5PZXHY59C3", - "role" => new RoleResponse("admin"), - "roles" => [ - new RoleResponse("admin"), - ], - "status" => "active", - "customAttributes" => [], - "directoryManaged" => false, - "createdAt" => "2021-06-25T19:07:33.155Z", - "updatedAt" => "2021-06-25T19:07:33.155Z", - ]; - } - - private function listAuthFactorResponseFixture() - { - return json_encode( - [ - "data" => [ - [ - "object" => "authentication_factor", - "id" => "auth_factor_01FXNWW32G7F3MG8MYK5D1HJJM", - "user_id" => "user_01H96FETWYSJMJEGF0Q3ZB272F", - "created_at" => "2022-03-08T23:12:20.157Z", - "updated_at" => "2022-03-08T23:12:20.157Z", - "type" => "totp", - "totp" => [ - "issuer" => "Foo Corp", - "user" => "user@foo-corp.com", - ] - ], - [ - "object" => "authentication_factor", - "id" => "auth_factor_01FXNWW32G7F3MG8MYK5D1HJJN", - "user_id" => "user_01H96FETWYSJMJEGF0Q3ZB272F", - "created_at" => "2022-03-08T23:12:20.157Z", - "updated_at" => "2022-03-08T23:12:20.157Z", - "type" => "totp", - "totp" => [ - "issuer" => "Bar Corp", - "user" => "user@bar-corp.com" - ] - ] - ] - ] - ); - } - - private function listAuthFactorFixture() - { - return [ - "object" => "authentication_factor", - "id" => "auth_factor_01FXNWW32G7F3MG8MYK5D1HJJM", - "userId" => "user_01H96FETWYSJMJEGF0Q3ZB272F", - "createdAt" => "2022-03-08T23:12:20.157Z", - "updatedAt" => "2022-03-08T23:12:20.157Z", - "type" => "totp", - "totp" => [ - "issuer" => "Foo Corp", - "user" => "user@foo-corp.com", - ] - ]; - } - - private function userResponseFixture() - { - return json_encode([ - "user" => [ - "object" => "user", - "id" => "user_01H7X1M4TZJN5N4HG4XXMA1234", - "email" => "test@test.com", - "first_name" => "Damien", - "last_name" => "Alabaster", - "email_verified" => true, - "profile_picture_url" => "https://example.com/photo.jpg", - "last_sign_in_at" => "2021-06-25T19:07:33.155Z", - "created_at" => "2021-06-25T19:07:33.155Z", - "updated_at" => "2021-06-25T19:07:33.155Z", - "external_id" => null, - "metadata" => [] - ] - ]); - } - - private function userAndImpersonatorResponseFixture() - { - return json_encode([ - "user" => [ - "object" => "user", - "id" => "user_01H7X1M4TZJN5N4HG4XXMA1234", - "email" => "test@test.com", - "first_name" => "Damien", - "last_name" => "Alabaster", - "email_verified" => true, - "profile_picture_url" => "https://example.com/photo.jpg", - "last_sign_in_at" => "2021-06-25T19:07:33.155Z", - "created_at" => "2021-06-25T19:07:33.155Z", - "updated_at" => "2021-06-25T19:07:33.155Z", - "external_id" => null, - "metadata" => [] - ], - "impersonator" => [ - "email" => "admin@foocorp.com", - "reason" => "Helping debug an account issue.", - ] - ]); - } - - private function userAndOAuthTokensResponseFixture() - { - return json_encode([ - "user" => [ - "object" => "user", - "id" => "user_01H7X1M4TZJN5N4HG4XXMA1234", - "email" => "test@test.com", - "first_name" => "Damien", - "last_name" => "Alabaster", - "email_verified" => true, - "profile_picture_url" => "https://example.com/photo.jpg", - "last_sign_in_at" => "2021-06-25T19:07:33.155Z", - "created_at" => "2021-06-25T19:07:33.155Z", - "updated_at" => "2021-06-25T19:07:33.155Z", - "external_id" => null, - "metadata" => [] - ], - "access_token" => "01DMEK0J53CVMC32CK5SE0KZ8Q", - "refresh_token" => "refresh_token_123", - "oauth_tokens" => [ - "access_token" => "oauth_access_token_123", - "refresh_token" => "oauth_refresh_token_456", - "expires_at" => 1640995200, - "scopes" => ["read", "write"] - ] - ]); - } - - private function createUserAndTokenResponseFixture() - { - return json_encode([ - "token" => "01DMEK0J53CVMC32CK5SE0KZ8Q", - "user" => [ - "object" => "user", - "id" => "user_01H7X1M4TZJN5N4HG4XXMA1234", - "email" => "test@test.com", - "first_name" => "Damien", - "last_name" => "Alabaster", - "email_verified" => true, - 'profile_picture_url' => 'https://example.com/photo.jpg', - "last_sign_in_at" => "2021-06-25T19:07:33.155Z", - "created_at" => "2021-06-25T19:07:33.155Z", - "updated_at" => "2021-06-25T19:07:33.155Z" - ] - ]); - } - - private function createUserResponseFixture() - { - return json_encode([ - "object" => "user", - "id" => "user_01H7X1M4TZJN5N4HG4XXMA1234", - "email" => "test@test.com", - "first_name" => "Damien", - "last_name" => "Alabaster", - "email_verified" => true, - 'profile_picture_url' => 'https://example.com/photo.jpg', - "last_sign_in_at" => "2021-06-25T19:07:33.155Z", - "created_at" => "2021-06-25T19:07:33.155Z", - "updated_at" => "2021-06-25T19:07:33.155Z", - "external_id" => null, - "metadata" => [] - ]); - } - - private function magicAuthResponseFixture() - { - return json_encode([ - "object" => "magic_auth", - "id" => "magic_auth_01E4ZCR3C56J083X43JQXF3JK5", - "user_id" => "user_01H7X1M4TZJN5N4HG4XXMA1234", - "email" => "someemail@test.com", - "expires_at" => "2021-07-01T19:07:33.155Z", - "code" => "123456", - "created_at" => "2021-07-01T19:07:33.155Z", - "updated_at" => "2021-07-01T19:07:33.155Z", - ]); - } - - private function magicAuthFixture() - { - return [ - "object" => "magic_auth", - "id" => "magic_auth_01E4ZCR3C56J083X43JQXF3JK5", - "userId" => "user_01H7X1M4TZJN5N4HG4XXMA1234", - "email" => "someemail@test.com", - "expiresAt" => "2021-07-01T19:07:33.155Z", - "code" => "123456", - "createdAt" => "2021-07-01T19:07:33.155Z", - "updatedAt" => "2021-07-01T19:07:33.155Z", - ]; - } - - private function emailVerificationResponseFixture() - { - return json_encode([ - "object" => "email_verification", - "id" => "email_verification_01E4ZCR3C56J083X43JQXF3JK5", - "user_id" => "user_01H7X1M4TZJN5N4HG4XXMA1234", - "email" => "someemail@test.com", - "expires_at" => "2021-07-01T19:07:33.155Z", - "code" => "123456", - "created_at" => "2021-07-01T19:07:33.155Z", - "updated_at" => "2021-07-01T19:07:33.155Z", - ]); - } - - private function emailVerificationFixture() - { - return [ - "object" => "email_verification", - "id" => "email_verification_01E4ZCR3C56J083X43JQXF3JK5", - "userId" => "user_01H7X1M4TZJN5N4HG4XXMA1234", - "email" => "someemail@test.com", - "expiresAt" => "2021-07-01T19:07:33.155Z", - "code" => "123456", - "createdAt" => "2021-07-01T19:07:33.155Z", - "updatedAt" => "2021-07-01T19:07:33.155Z", - ]; - } - - private function passwordResetResponseFixture() - { - return json_encode([ - "object" => "password_reset", - "id" => "password_reset_01E4ZCR3C56J083X43JQXF3JK5", - "user_id" => "user_01H7X1M4TZJN5N4HG4XXMA1234", - "email" => "someemail@test.com", - "password_reset_token" => "Z1uX3RbwcIl5fIGJJJCXXisdI", - "password_reset_url" => "https://your-app.com/reset-password?token=Z1uX3RbwcIl5fIGJJJCXXisdI", - "expires_at" => "2021-07-01T19:07:33.155Z", - "created_at" => "2021-07-01T19:07:33.155Z", - ]); - } - - private function passwordResetFixture() - { - return [ - "object" => "password_reset", - "id" => "password_reset_01E4ZCR3C56J083X43JQXF3JK5", - "userId" => "user_01H7X1M4TZJN5N4HG4XXMA1234", - "email" => "someemail@test.com", - "passwordResetToken" => "Z1uX3RbwcIl5fIGJJJCXXisdI", - "passwordResetUrl" => "https://your-app.com/reset-password?token=Z1uX3RbwcIl5fIGJJJCXXisdI", - "expiresAt" => "2021-07-01T19:07:33.155Z", - "createdAt" => "2021-07-01T19:07:33.155Z", - ]; - } - - private function sendMagicAuthCodeResponseFixture() - { - return json_encode([ - "object" => "magic_auth_challenge", - "id" => "auth_challenge_01E4ZCR3C56J083X43JQXF3JK5" - ]); - } - - private function getUserResponseFixture() - { - return json_encode([ - "object" => "user", - "id" => "user_01H7X1M4TZJN5N4HG4XXMA1234", - "email" => "test@test.com", - "first_name" => "Damien", - "last_name" => "Alabaster", - "email_verified" => true, - "profile_picture_url" => "https://example.com/photo.jpg", - "last_sign_in_at" => "2021-06-25T19:07:33.155Z", - "created_at" => "2021-06-25T19:07:33.155Z", - "updated_at" => "2021-06-25T19:07:33.155Z", - "external_id" => null, - "metadata" => [] - ]); - } - - private function listUsersResponseFixture() - { - return json_encode([ - "data" => [ - [ - "object" => "user", - "id" => "user_01H7X1M4TZJN5N4HG4XXMA1234", - "email" => "test@test.com", - "first_name" => "Damien", - "last_name" => "Alabaster", - "email_verified" => true, - "profile_picture_url" => "https://example.com/photo.jpg", - "last_sign_in_at" => "2021-06-25T19:07:33.155Z", - "created_at" => "2021-06-25T19:07:33.155Z", - "updated_at" => "2021-06-25T19:07:33.155Z", - "external_id" => null, - "metadata" => [] - ] - ], - "list_metadata" => [ - "before" => null, - "after" => null - ], - ]); - } - - private function magicAuthChallengeFixture() - { - return [ - "object" => "magic_auth_challenge", - "id" => "auth_challenge_01E4ZCR3C56J083X43JQXF3JK5" - ]; - } - - private function userFixture() - { - return [ - "object" => "user", - "id" => "user_01H7X1M4TZJN5N4HG4XXMA1234", - "email" => "test@test.com", - "firstName" => "Damien", - "lastName" => "Alabaster", - "emailVerified" => true, - "profilePictureUrl" => "https://example.com/photo.jpg", - "lastSignInAt" => "2021-06-25T19:07:33.155Z", - "createdAt" => "2021-06-25T19:07:33.155Z", - "updatedAt" => "2021-06-25T19:07:33.155Z", - "externalId" => null, - "metadata" => [] - ]; - } - - private function userAndOrgResponseFixture() - { - return json_encode([ - "user" => [ - "object" => "user", - "id" => "user_01H7X1M4TZJN5N4HG4XXMA1234", - "email" => "test@test.com", - "first_name" => "Damien", - "last_name" => "Alabaster", - "email_verified" => true, - "profile_picture_url" => "https://example.com/photo.jpg", - "last_sign_in_at" => "2021-06-25T19:07:33.155Z", - "created_at" => "2021-06-25T19:07:33.155Z", - "updated_at" => "2021-06-25T19:07:33.155Z", - "external_id" => null, - "metadata" => [] - ], - "organization_id" => "org_01EHQMYV6MBK39QC5PZXHY59C3", - ]); - } - - - private function enrollAuthFactorResponseFixture() - { - return json_encode([ - "authentication_factor" => [ - "object" => "authentication_factor", - "id" => "auth_factor_01FXNWW32G7F3MG8MYK5D1HJJM", - "created_at" => "2022-03-08T23:12:20.157Z", - "updated_at" => "2022-03-08T23:12:20.157Z", - "type" => "totp", - "totp" => [ - "qr_code" => "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAApAAAAKQCAYAAAAotUpQAAAAAklEQVR4AewaftIAABPuSURBVO3B0Y0s2w0EsCrh5Z+y7BR0z0djsCSbZMPP2t18qW2+tLt50TYvdjdfaptftrt50TYvdjcv2obv7G5etM2L3c2X2ubF7uZLbcPvmgAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4GACAAAH/+XR7oZ/1zZ8Z3fzom1e7G5e7G5etA3f2d38srb5ZbubL7XNi93Ni7Z5sbv50u6Gf9c2LyYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwX/5WNv8st3NL2ubL+1uXrTNl3Y3X2qbX9Y2f1nb/GW7mxdt86XdDb+rbX7Z7uZLEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAODgv8CD3c2Xdjcv2uYv2938ZW3zpd3NX9Y2L3Y3/LvdDfyrCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHDwX+BB27zY3Xxpd/PLdjcv2ubF7uZF2/xlbfPLdjcvdjdfaptf1jZf2t3wd00AAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAg//ysd0Nv2t388va5sXu5kXbvNjdvNjdfGl386W2+WW7mxdt88va5pftbvjO7oZ/NwEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIPu/+VDbfOl3c2LtuE7u5svtc1ftrt50TYvdjcv2uaX7W5+Wdt8aXfDv2sb/q4JAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcPBfftzu5pftbl60zYvdzV/WNl/a3bxom7+sbV7sbl60zZfa5ku7m1/WNi92N19qmxe7m1+2u3nRNl/a3bxomy9NAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMm2fyw3c2LtuF37W6+1DZf2t28aJsXu5sXbfNid/OibV7sbn5Z2/Cd3c2Ltnmxu3nRNi92Ny/a5sXu5kXb/LLdzYsJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHDTJhp+1u3nRNl/a3bxomy/tbn5Z2/yy3c0va5sXu5sXbfOX7W5etM2L3c2Ltnmxu/nL2uaX7W6+NAEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAO/gfiF4JV0SXN7wAAAABJRU5ErkJggg==", - "secret" => "JJWBYBLLH5TRKYZEGMREU6DRKFRVMTCV", - "uri" => "otpauth://totp/test:example?secret=JJWBYBLLH5TRKYZEGMREU6DRKFRVMTCV&issuer=test" - ] - ], - "authentication_challenge" => [ - "object" => "authentication_challenge", - "id" => "auth_challenge_01FXNX3BTZPPJVKF65NNWGRHZJ", - "created_at" => "2022-03-08T23:16:18.532Z", - "updated_at" => "2022-03-08T23:16:18.532Z", - "expires_at" => "2022-03-08T23:16:18.532Z", - "authentication_factor_id" => "auth_factor_01FXNWW32G7F3MG8MYK5D1HJJM" - ], - ]); - } - - private function enrollAuthFactorFixture() - { - return [ - "object" => "authentication_factor", - "id" => "auth_factor_01FXNWW32G7F3MG8MYK5D1HJJM", - "createdAt" => "2022-03-08T23:12:20.157Z", - "updatedAt" => "2022-03-08T23:12:20.157Z", - "type" => "totp", - "totp" => [ - "qr_code" => "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAApAAAAKQCAYAAAAotUpQAAAAAklEQVR4AewaftIAABPuSURBVO3B0Y0s2w0EsCrh5Z+y7BR0z0djsCSbZMPP2t18qW2+tLt50TYvdjdfaptftrt50TYvdjcv2obv7G5etM2L3c2X2ubF7uZLbcPvmgAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4GACAAAH/+XR7oZ/1zZ8Z3fzom1e7G5e7G5etA3f2d38srb5ZbubL7XNi93Ni7Z5sbv50u6Gf9c2LyYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwX/5WNv8st3NL2ubL+1uXrTNl3Y3X2qbX9Y2f1nb/GW7mxdt86XdDb+rbX7Z7uZLEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAODgv8CD3c2Xdjcv2uYv2938ZW3zpd3NX9Y2L3Y3/LvdDfyrCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHDwX+BB27zY3Xxpd/PLdjcv2ubF7uZF2/xlbfPLdjcvdjdfaptf1jZf2t3wd00AAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAg//ysd0Nv2t388va5sXu5kXbvNjdvNjdfGl386W2+WW7mxdt88va5pftbvjO7oZ/NwEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIPu/+VDbfOl3c2LtuE7u5svtc1ftrt50TYvdjcv2uaX7W5+Wdt8aXfDv2sb/q4JAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcPBfftzu5pftbl60zYvdzV/WNl/a3bxom7+sbV7sbl60zZfa5ku7m1/WNi92N19qmxe7m1+2u3nRNl/a3bxomy9NAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHEwAAOBgAgAABxMAADiYAADAwQQAAA4mAABwMAEAgIMm2fyw3c2LtuF37W6+1DZf2t28aJsXu5sXbfNid/OibV7sbn5Z2/Cd3c2Ltnmxu3nRNi92Ny/a5sXu5kXb/LLdzYsJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAOJgAAcDABAICDCQAAHDTJhp+1u3nRNl/a3bxomy/tbn5Z2/yy3c0va5sXu5sXbfOX7W5etM2L3c2Ltnmxu/nL2uaX7W6+NAEAgIMJAAAcTAAA4GACAAAHEwAAOJgAAMDBBAAADiYAAHAwAQCAgwkAABxMAADgYAIAAAcTAAA4mAAAwMEEAAAO/gfiF4JV0SXN7wAAAABJRU5ErkJggg==", - "secret" => "JJWBYBLLH5TRKYZEGMREU6DRKFRVMTCV", - "uri" => "otpauth://totp/test:example?secret=JJWBYBLLH5TRKYZEGMREU6DRKFRVMTCV&issuer=test" - ] - ]; - } - - private function enrollAuthChallengeFixture() - { - return [ - "object" => "authentication_challenge", - "id" => "auth_challenge_01FXNX3BTZPPJVKF65NNWGRHZJ", - "createdAt" => "2022-03-08T23:16:18.532Z", - "updatedAt" => "2022-03-08T23:16:18.532Z", - "expiresAt" => "2022-03-08T23:16:18.532Z", - "authenticationFactorId" => "auth_factor_01FXNWW32G7F3MG8MYK5D1HJJM" - ]; - } - - // Session Management Tests - - public function testListSessions() - { - $userId = "user_01H7X1M4TZJN5N4HG4XXMA1234"; - $path = "user_management/users/{$userId}/sessions"; - - $result = json_encode([ - "data" => [ - [ - "id" => "session_01H7X1M4TZJN5N4HG4XXMA1234", - "user_id" => $userId, - "ip_address" => "192.168.1.1", - "user_agent" => "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", - "organization_id" => "org_01H7X1M4TZJN5N4HG4XXMA9876", - "authentication_method" => "SSO", - "status" => "active", - "expires_at" => "2026-02-01T00:00:00.000Z", - "ended_at" => null, - "created_at" => "2026-01-01T00:00:00.000Z", - "updated_at" => "2026-01-01T00:00:00.000Z", - "object" => "session" - ], - [ - "id" => "session_01H7X1M4TZJN5N4HG4XXMA5678", - "user_id" => $userId, - "ip_address" => "192.168.1.2", - "user_agent" => "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)", - "organization_id" => null, - "authentication_method" => "Password", - "status" => "active", - "expires_at" => "2026-02-01T00:00:00.000Z", - "ended_at" => null, - "created_at" => "2026-01-01T00:00:00.000Z", - "updated_at" => "2026-01-01T00:00:00.000Z", - "object" => "session" - ] - ], - "list_metadata" => ["before" => null, "after" => null] - ]); - - $this->mockRequest( - Client::METHOD_GET, - $path, - null, - ["limit" => 10, "before" => null, "after" => null, "order" => null], - true, - $result - ); - - list($before, $after, $sessions) = $this->userManagement->listSessions($userId); - - $this->assertCount(2, $sessions); - $this->assertInstanceOf(Resource\Session::class, $sessions[0]); - $this->assertEquals("session_01H7X1M4TZJN5N4HG4XXMA1234", $sessions[0]->id); - $this->assertEquals("active", $sessions[0]->status); - $this->assertEquals("192.168.1.1", $sessions[0]->ipAddress); - $this->assertEquals("SSO", $sessions[0]->authenticationMethod); - } - - public function testRevokeSession() - { - $sessionId = "session_01H7X1M4TZJN5N4HG4XXMA1234"; - $path = "user_management/sessions/revoke"; - - $result = json_encode([ - "id" => $sessionId, - "user_id" => "user_01H7X1M4TZJN5N4HG4XXMA1234", - "ip_address" => "192.168.1.1", - "user_agent" => "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", - "organization_id" => null, - "authentication_method" => "Password", - "status" => "inactive", - "expires_at" => "2026-02-01T00:00:00.000Z", - "ended_at" => "2026-01-05T12:00:00.000Z", - "created_at" => "2026-01-01T00:00:00.000Z", - "updated_at" => "2026-01-05T12:00:00.000Z", - "object" => "session" - ]); - - $this->mockRequest( - Client::METHOD_POST, - $path, - null, - [ "session_id" => $sessionId ], - true, - $result - ); - - $session = $this->userManagement->revokeSession($sessionId); - - $this->assertInstanceOf(Resource\Session::class, $session); - $this->assertEquals($sessionId, $session->id); - $this->assertEquals("inactive", $session->status); - $this->assertNotNull($session->endedAt); - $this->assertEquals("2026-01-05T12:00:00.000Z", $session->endedAt); - } - - public function testAuthenticateWithSessionCookieNoSessionProvided() - { - $result = $this->userManagement->authenticateWithSessionCookie("", "password"); - - $this->assertInstanceOf( - Resource\SessionAuthenticationFailureResponse::class, - $result - ); - $this->assertFalse($result->authenticated); - $this->assertEquals( - Resource\SessionAuthenticationFailureResponse::REASON_NO_SESSION_COOKIE_PROVIDED, - $result->reason - ); - } - - public function testLoadSealedSession() - { - $sessionData = [ - 'access_token' => 'test_access_token_12345', - 'refresh_token' => 'test_refresh_token_67890', - 'session_id' => 'session_01H7X1M4TZJN5N4HG4XXMA1234' - ]; - $cookiePassword = 'test-password-for-encryption-with-minimum-length'; - - // Use encryptor directly (sealing is authkit-php's responsibility) - $encryptor = new Session\HaliteSessionEncryption(); - $sealed = $encryptor->seal($sessionData, $cookiePassword); - $cookieSession = $this->userManagement->loadSealedSession($sealed, $cookiePassword); - - $this->assertInstanceOf(CookieSession::class, $cookieSession); - } - - public function testGetSessionFromCookieWithNoCookie() - { - $cookiePassword = 'test-password-for-encryption-with-minimum-length'; - - // Ensure no cookie is set - if (isset($_COOKIE['wos-session'])) { - unset($_COOKIE['wos-session']); - } - - $result = $this->userManagement->getSessionFromCookie($cookiePassword); - - $this->assertNull($result); - } - - public function testGetSessionFromCookieWithCookie() - { - $sessionData = [ - 'access_token' => 'test_access_token_12345', - 'refresh_token' => 'test_refresh_token_67890', - 'session_id' => 'session_01H7X1M4TZJN5N4HG4XXMA1234' - ]; - $cookiePassword = 'test-password-for-encryption-with-minimum-length'; - - // Use encryptor directly (sealing is authkit-php's responsibility) - $encryptor = new Session\HaliteSessionEncryption(); - $sealed = $encryptor->seal($sessionData, $cookiePassword); - - // Simulate cookie being set - $_COOKIE['wos-session'] = $sealed; - - $cookieSession = $this->userManagement->getSessionFromCookie($cookiePassword); - - $this->assertInstanceOf(CookieSession::class, $cookieSession); - - // Cleanup - unset($_COOKIE['wos-session']); - } - - public function testConstructorWithCustomEncryptor() - { - $mockEncryptor = $this->createMock(Session\SessionEncryptionInterface::class); - $mockEncryptor->method('unseal') - ->willReturn(['access_token' => 'test', 'refresh_token' => 'test']); - - // Create fresh HTTP client mock to throw exception - $httpMock = $this->createMock(\WorkOS\RequestClient\RequestClientInterface::class); - $response = new Resource\Response('{"error": "server_error"}', [], 500); - $httpMock->method('request') - ->willThrowException(new Exception\ServerException($response)); - Client::setRequestClient($httpMock); - - $userManagement = new UserManagement($mockEncryptor); - - // The custom encryptor should be used for authentication - // Mock will succeed on unseal, but API call will fail - we just verify no encryption error - $result = $userManagement->authenticateWithSessionCookie('any_sealed_data', 'password'); - - // Should get past encryption (HTTP error expected, not encryption error) - $this->assertInstanceOf( - Resource\SessionAuthenticationFailureResponse::class, - $result - ); - $this->assertEquals( - Resource\SessionAuthenticationFailureResponse::REASON_HTTP_ERROR, - $result->reason - ); - } - - public function testSetSessionEncryptor() - { - $mockEncryptor = $this->createMock(Session\SessionEncryptionInterface::class); - $mockEncryptor->method('unseal') - ->willReturn(['access_token' => 'test', 'refresh_token' => 'test']); - - // Create fresh HTTP client mock to throw exception - $httpMock = $this->createMock(\WorkOS\RequestClient\RequestClientInterface::class); - $response = new Resource\Response('{"error": "server_error"}', [], 500); - $httpMock->method('request') - ->willThrowException(new Exception\ServerException($response)); - Client::setRequestClient($httpMock); - - $userManagement = new UserManagement(); - $userManagement->setSessionEncryptor($mockEncryptor); - - // The custom encryptor should be used for authentication - $result = $userManagement->authenticateWithSessionCookie('any_sealed_data', 'password'); - - // Should get past encryption (HTTP error expected, not encryption error) - $this->assertInstanceOf( - Resource\SessionAuthenticationFailureResponse::class, - $result - ); - $this->assertEquals( - Resource\SessionAuthenticationFailureResponse::REASON_HTTP_ERROR, - $result->reason - ); - } - - public function testAuthenticateWithSessionCookieEncryptionError() - { - $mockEncryptor = $this->createMock(Session\SessionEncryptionInterface::class); - $mockEncryptor->method('unseal') - ->willThrowException(new \Exception('Decryption failed')); - - $userManagement = new UserManagement($mockEncryptor); - $result = $userManagement->authenticateWithSessionCookie('invalid_sealed_data', 'password'); - - $this->assertInstanceOf( - Resource\SessionAuthenticationFailureResponse::class, - $result - ); - $this->assertFalse($result->authenticated); - $this->assertEquals( - Resource\SessionAuthenticationFailureResponse::REASON_ENCRYPTION_ERROR, - $result->reason - ); - } - - public function testAuthenticateWithSessionCookieHttpError() - { - $sessionData = [ - 'access_token' => 'test_access_token_12345', - 'refresh_token' => 'test_refresh_token_67890' - ]; - $cookiePassword = 'test-password-for-encryption-with-minimum-length'; - - // Use encryptor directly (sealing is authkit-php's responsibility) - $encryptor = new Session\HaliteSessionEncryption(); - $sealed = $encryptor->seal($sessionData, $cookiePassword); - - // Set up mock to throw HTTP exception on API call - $response = new Resource\Response('{"error": "server_error"}', [], 500); - Client::setRequestClient($this->requestClientMock); - $this->requestClientMock - ->expects($this->atLeastOnce()) - ->method('request') - ->willThrowException(new Exception\ServerException($response)); - - $result = $this->userManagement->authenticateWithSessionCookie($sealed, $cookiePassword); - - $this->assertInstanceOf( - Resource\SessionAuthenticationFailureResponse::class, - $result - ); - $this->assertFalse($result->authenticated); - $this->assertEquals( - Resource\SessionAuthenticationFailureResponse::REASON_HTTP_ERROR, - $result->reason - ); - } -} diff --git a/tests/WorkOS/VaultTest.php b/tests/WorkOS/VaultTest.php deleted file mode 100644 index 2160b354..00000000 --- a/tests/WorkOS/VaultTest.php +++ /dev/null @@ -1,205 +0,0 @@ -traitSetUp(); - - $this->withApiKey(); - $this->vault = new Vault(); - } - - public function testGetVaultObject() - { - $vaultObjectPath = "vault/v1/kv/vault_obj_01EHQMYV6MBK39QC5PZXHY59C3"; - - $result = $this->vaultObjectResponseFixture(); - - $this->mockRequest( - Client::METHOD_GET, - $vaultObjectPath, - null, - null, - true, - $result - ); - - $vaultObject = $this->vaultObjectFixture(); - - $response = $this->vault->getVaultObject("vault_obj_01EHQMYV6MBK39QC5PZXHY59C3"); - $this->assertSame($vaultObject, $response->toArray()); - } - - public function testListVaultObjects() - { - $vaultObjectsPath = "vault/v1/kv"; - - $result = $this->vaultObjectsResponseFixture(); - - $params = [ - "limit" => 10, - "before" => null, - "after" => null, - "order" => null - ]; - - $this->mockRequest( - Client::METHOD_GET, - $vaultObjectsPath, - null, - $params, - true, - $result - ); - - $vaultObjects = $this->vaultObjectsFixture(); - - list($before, $after, $response) = $this->vault->listVaultObjects(); - $this->assertSame($vaultObjects, $response[0]->toArray()); - } - - public function testListVaultObjectsPaginatedResourceAccessPatterns() - { - $vaultObjectsPath = "vault/v1/kv"; - $result = $this->vaultObjectsResponseFixture(); - $params = [ - "limit" => 10, - "before" => null, - "after" => null, - "order" => null - ]; - - $this->mockRequest( - Client::METHOD_GET, - $vaultObjectsPath, - null, - $params, - true, - $result - ); - - // Test 1: Bare destructuring (indexed) - [$before1, $after1, $objects1] = $this->vault->listVaultObjects(); - $this->assertNull($before1); - $this->assertNull($after1); - $this->assertIsArray($objects1); - $this->assertCount(1, $objects1); - - // Mock the request again for the next test - $this->mockRequest( - Client::METHOD_GET, - $vaultObjectsPath, - null, - $params, - true, - $result - ); - - // Test 2: Named destructuring - ["before" => $before2, "after" => $after2, "vault_objects" => $objects2] = $this->vault->listVaultObjects(); - $this->assertNull($before2); - $this->assertNull($after2); - $this->assertIsArray($objects2); - $this->assertCount(1, $objects2); - - // Mock the request again for the next test - $this->mockRequest( - Client::METHOD_GET, - $vaultObjectsPath, - null, - $params, - true, - $result - ); - - // Test 3: Fluent access - $response = $this->vault->listVaultObjects(); - $this->assertNull($response->before); - $this->assertNull($response->after); - $this->assertIsArray($response->vault_objects); - $this->assertCount(1, $response->vault_objects); - - // Test 4: Generic data accessor - $this->assertIsArray($response->data); - $this->assertSame($response->vault_objects, $response->data); - } - - - - - - - - // Fixtures - - private function vaultObjectResponseFixture() - { - return json_encode([ - "id" => "vault_obj_01EHQMYV6MBK39QC5PZXHY59C3", - "name" => "Test Vault Object", - "updated_at" => "2024-01-01T00:00:00.000Z", - "value" => null, - "metadata" => [] - ]); - } - - private function vaultObjectFixture() - { - return [ - "id" => "vault_obj_01EHQMYV6MBK39QC5PZXHY59C3", - "name" => "Test Vault Object", - "updatedAt" => "2024-01-01T00:00:00.000Z", - "value" => null, - "metadata" => [] - ]; - } - - private function vaultObjectsResponseFixture() - { - return json_encode([ - "object" => "list", - "data" => [ - [ - "id" => "vault_obj_01EHQMYV6MBK39QC5PZXHY59C3", - "name" => "Test Vault Object", - "updated_at" => "2024-01-01T00:00:00.000Z", - "value" => null, - "metadata" => [] - ] - ], - "list_metadata" => [ - "before" => null, - "after" => null - ] - ]); - } - - private function vaultObjectsFixture() - { - return [ - "id" => "vault_obj_01EHQMYV6MBK39QC5PZXHY59C3", - "name" => "Test Vault Object", - "updatedAt" => "2024-01-01T00:00:00.000Z", - "value" => null, - "metadata" => [] - ]; - } - - - - -} diff --git a/tests/WorkOS/WebhookTest.php b/tests/WorkOS/WebhookTest.php deleted file mode 100644 index 27693bb6..00000000 --- a/tests/WorkOS/WebhookTest.php +++ /dev/null @@ -1,118 +0,0 @@ -traitSetUp(); - - $this->withApiKey(); - $this->ap = new Webhook(); - - $this->payload = '{"id":"wh_01FGCG6SDYCT5XWZT9CDW0XEB8","data":{"id":"conn_01EHWNC0FCBHZ3BJ7EGKYXK0E6","name":"Foo Corp\'s Connection","state":"active","object":"connection","domains":[{"id":"conn_domain_01EHWNFTAFCF3CQAE5A9Q0P1YB","domain":"foo-corp.com","object":"connection_domain"}],"connection_type":"OktaSAML","organization_id":"org_01EHWNCE74X7JSDV0X3SZ3KJNY"},"event":"connection.activated"}'; - $this->secret = 'secret'; - $this->tolerance = 180; - $this->time = time(); - $decodedBody = $this->payload; - $signedPayload = $this->time . "." . $decodedBody; - $this->expectedSignature = hash_hmac("sha256", $signedPayload, $this->secret, false); - $this->sigHeader = 't=' . $this->time . ', v1=' . $this->expectedSignature; - } - - public function testConstructEventWebhook() - { - $result = $this->generateConnectionFixture(); - - $expectation = $this->payload; - - $response = $this->ap->constructEvent($this->sigHeader, $this->payload, $this->secret, $this->tolerance); - $this->assertSame($expectation, json_encode($response)); - } - - public function testVerifyHeaderWebhook() - { - $expectation = 'pass'; - - $response = $this->ap->verifyHeader($this->sigHeader, $this->payload, $this->secret, $this->tolerance); - $this->assertSame($expectation, $response); - } - - public function testGetTimeStamp() - { - $expectation = strval($this->time); - - $response = $this->ap->getTimeStamp($this->sigHeader); - $this->assertSame($expectation, $response); - } - - public function testGetSignature() - { - $expectation = $this->expectedSignature; - - $response = $this->ap->getSignature($this->sigHeader); - $this->assertSame($expectation, $response); - } - - // Fixtures - - private function generateConnectionFixture() - { - return json_encode([ - "id" => "conn_01E0CG2C820RP4VS50PRJF8YPX", - "domains" => [ - [ - "id" => "conn_dom_01E2GCC7Q3KCNEFA2BW9MXR4T5", - "domain" => "workos.com" - ] - ], - "state" => "active", - "status" => "linked", - "name" => "Google OAuth 2.0", - "connectionType" => "GoogleOAuth", - "organizationId" => "org_1234", - ]); - } -} diff --git a/tests/WorkOS/WidgetsTest.php b/tests/WorkOS/WidgetsTest.php deleted file mode 100644 index 215e44e8..00000000 --- a/tests/WorkOS/WidgetsTest.php +++ /dev/null @@ -1,61 +0,0 @@ -traitSetUp(); - - $this->withApiKey(); - $this->ap = new Widgets(); - } - - public function testGenerateLinkSSO() - { - $getTokenPath = "widgets/token"; - - $result = $this->generateWidgetTokenFixture(); - - $params = [ - "organization_id" => "org_01EHZNVPK3SFK441A1RGBFSHRT", - "user_id" => "user_01EHZNVPK3SFK441A1RGBFSHRT", - "scopes" => ["widgets:users-table:manage"] - ]; - - $this->mockRequest( - Client::METHOD_POST, - $getTokenPath, - null, - $params, - true, - $result - ); - - $expectation = "abc123456"; - - $response = $this->ap->getToken("org_01EHZNVPK3SFK441A1RGBFSHRT", "user_01EHZNVPK3SFK441A1RGBFSHRT", ["widgets:users-table:manage"]); - $this->assertSame($expectation, $response->token); - } - - // Fixtures - - private function generateWidgetTokenFixture() - { - return json_encode([ - "token" => "abc123456" - ]); - } -} diff --git a/tests/WorkOS/WorkOSTest.php b/tests/WorkOS/WorkOSTest.php deleted file mode 100644 index 2385aee0..00000000 --- a/tests/WorkOS/WorkOSTest.php +++ /dev/null @@ -1,59 +0,0 @@ -assertEquals("pk_test_env_superglobal", WorkOS::getApiKey()); - } - - public function testGetClientIdFromEnvSuperglobal() - { - $_ENV['WORKOS_CLIENT_ID'] = "client_test_env_superglobal"; - - $this->assertEquals("client_test_env_superglobal", WorkOS::getClientId()); - } - - public function testLaravelConfigCachingScenario() - { - $_ENV['WORKOS_API_KEY'] = "pk_test_laravel_cached"; - $_ENV['WORKOS_CLIENT_ID'] = "client_test_laravel_cached"; - - $this->assertEquals("pk_test_laravel_cached", WorkOS::getApiKey()); - $this->assertEquals("client_test_laravel_cached", WorkOS::getClientId()); - } -} diff --git a/tests/bootstrap.php b/tests/bootstrap.php index d316016f..ee443918 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,3 +1,5 @@