From 11d260ad53fa56e985c75044bb3c5d3a9a0e7eb4 Mon Sep 17 00:00:00 2001 From: Katie West Date: Fri, 25 Sep 2026 09:24:51 -0700 Subject: [PATCH] feat(directory-sync): Add on-demand sync (FEAT-3084) --- .oagen-manifest.json | 8 ++++ lib/Resource/DirectorySyncRateLimitError.php | 40 +++++++++++++++++++ lib/Resource/DirectorySyncResponse.php | 32 +++++++++++++++ lib/Service/DirectorySync.php | 21 ++++++++++ .../directory_sync_rate_limit_error.json | 5 +++ tests/Fixtures/directory_sync_response.json | 3 ++ tests/Service/DirectorySyncTest.php | 12 ++++++ 7 files changed, 121 insertions(+) create mode 100644 lib/Resource/DirectorySyncRateLimitError.php create mode 100644 lib/Resource/DirectorySyncResponse.php create mode 100644 tests/Fixtures/directory_sync_rate_limit_error.json create mode 100644 tests/Fixtures/directory_sync_response.json diff --git a/.oagen-manifest.json b/.oagen-manifest.json index 07a40923..92a9e96e 100644 --- a/.oagen-manifest.json +++ b/.oagen-manifest.json @@ -314,6 +314,8 @@ "lib/Resource/DirectoryMetadata.php", "lib/Resource/DirectoryMetadataUser.php", "lib/Resource/DirectoryState.php", + "lib/Resource/DirectorySyncRateLimitError.php", + "lib/Resource/DirectorySyncResponse.php", "lib/Resource/DirectoryType.php", "lib/Resource/DirectoryUser.php", "lib/Resource/DirectoryUserEmail.php", @@ -1009,6 +1011,8 @@ "tests/Fixtures/directory_group.json", "tests/Fixtures/directory_metadata.json", "tests/Fixtures/directory_metadata_user.json", + "tests/Fixtures/directory_sync_rate_limit_error.json", + "tests/Fixtures/directory_sync_response.json", "tests/Fixtures/directory_user.json", "tests/Fixtures/directory_user_email.json", "tests/Fixtures/directory_user_with_groups.json", @@ -2447,6 +2451,10 @@ "GET /audit_logs/exports/{auditLogExportId}": { "sdkMethod": "getExport", "service": "auditLogs" + }, + "POST /directories/{id}/sync": { + "sdkMethod": "syncDirectory", + "service": "directorySync" } } } diff --git a/lib/Resource/DirectorySyncRateLimitError.php b/lib/Resource/DirectorySyncRateLimitError.php new file mode 100644 index 00000000..fb7e60c5 --- /dev/null +++ b/lib/Resource/DirectorySyncRateLimitError.php @@ -0,0 +1,40 @@ + $this->code, + 'message' => $this->message, + 'retry_after_seconds' => $this->retryAfterSeconds, + ]; + } +} diff --git a/lib/Resource/DirectorySyncResponse.php b/lib/Resource/DirectorySyncResponse.php new file mode 100644 index 00000000..991b9a2b --- /dev/null +++ b/lib/Resource/DirectorySyncResponse.php @@ -0,0 +1,32 @@ + $this->status, + ]; + } +} diff --git a/lib/Service/DirectorySync.php b/lib/Service/DirectorySync.php index d2ed0ed6..ef1565e6 100644 --- a/lib/Service/DirectorySync.php +++ b/lib/Service/DirectorySync.php @@ -8,6 +8,7 @@ use WorkOS\Resource\Directory; use WorkOS\Resource\DirectoryGroup; +use WorkOS\Resource\DirectorySyncResponse; use WorkOS\Resource\DirectoryUserWithGroups; class DirectorySync @@ -98,6 +99,26 @@ public function deleteDirectory( ); } + /** + * Sync a Directory + * + * Request an asynchronous sync from the directory provider. Currently supports Google Workspace directories in linked or validating state. Manual requests share a five-minute per-directory cooldown across the API, Dashboard, Admin Portal, and MCP. Acceptance means the request was queued, not that the sync has started or completed. A running sync prevents another request from being queued. + * @param string $id Unique identifier for the Directory. + * @return \WorkOS\Resource\DirectorySyncResponse + * @throws \WorkOS\Exception\WorkOSException + */ + public function syncDirectory( + string $id, + ?\WorkOS\RequestOptions $options = null, + ): \WorkOS\Resource\DirectorySyncResponse { + $response = $this->client->request( + method: 'POST', + path: 'directories/' . rawurlencode($id) . '/sync', + options: $options, + ); + return DirectorySyncResponse::fromArray($response); + } + /** * List Directory Groups * diff --git a/tests/Fixtures/directory_sync_rate_limit_error.json b/tests/Fixtures/directory_sync_rate_limit_error.json new file mode 100644 index 00000000..4e136b93 --- /dev/null +++ b/tests/Fixtures/directory_sync_rate_limit_error.json @@ -0,0 +1,5 @@ +{ + "code": "directory_sync_rate_limited", + "message": "Request could not be processed.", + "retry_after_seconds": 120 +} diff --git a/tests/Fixtures/directory_sync_response.json b/tests/Fixtures/directory_sync_response.json new file mode 100644 index 00000000..ef041155 --- /dev/null +++ b/tests/Fixtures/directory_sync_response.json @@ -0,0 +1,3 @@ +{ + "status": "queued" +} diff --git a/tests/Service/DirectorySyncTest.php b/tests/Service/DirectorySyncTest.php index 8198316b..a7a145c3 100644 --- a/tests/Service/DirectorySyncTest.php +++ b/tests/Service/DirectorySyncTest.php @@ -55,6 +55,18 @@ public function testDeleteDirectory(): void $this->assertStringEndsWith('directories/test_id', $request->getUri()->getPath()); } + public function testSyncDirectory(): void + { + $fixture = $this->loadFixture('directory_sync_response'); + $client = $this->createMockClient([['status' => 200, 'body' => $fixture]]); + $result = $client->directorySync()->syncDirectory('test_id'); + $this->assertInstanceOf(\WorkOS\Resource\DirectorySyncResponse::class, $result); + $this->assertIsArray($result->toArray()); + $request = $this->getLastRequest(); + $this->assertSame('POST', $request->getMethod()); + $this->assertStringEndsWith('directories/test_id/sync', $request->getUri()->getPath()); + } + public function testListGroups(): void { $fixture = $this->loadFixture('list_directory_group');