, retry_after:?int} */ public static function resolve( string $cep ): array { $cached = get_transient( self::CACHE_PREFIX . $cep ); if ( is_array( $cached ) ) { return isset( $cached['miss'] ) ? self::not_found() : array( 'status' => 200, 'body' => $cached, 'retry_after' => null, ); } try { $address = self::client()->lookup( $cep ); } catch ( Cepis\CepNotFoundException ) { set_transient( self::CACHE_PREFIX . $cep, array( 'miss' => true ), self::MISS_TTL ); return self::not_found(); } catch ( Cepis\InvalidCepException ) { return array( 'status' => 400, 'body' => array( 'erro' => 'cep_invalido', 'mensagem' => 'CEP deve ter 8 dígitos', ), 'retry_after' => null, ); } catch ( Cepis\RateLimitedException $e ) { return array( 'status' => 429, 'body' => array( 'erro' => 'limite', 'mensagem' => 'Muitas consultas em pouco tempo', ), 'retry_after' => null === $e->retryAfter ? null : (int) $e->retryAfter, ); } catch ( Cepis\CepisException ) { return array( 'status' => 502, 'body' => array( 'erro' => 'interno', 'mensagem' => 'falha interna', ), 'retry_after' => null, ); } $body = $address->raw; set_transient( self::CACHE_PREFIX . $cep, $body, self::HIT_TTL ); return array( 'status' => 200, 'body' => $body, 'retry_after' => null, ); } /** * Drop every cached answer. * * Used by the settings screen when the API root changes, since answers from * one instance say nothing about another. */ public static function flush(): void { global $wpdb; $like = $wpdb->esc_like( '_transient_' . self::CACHE_PREFIX ) . '%'; $names = $wpdb->get_col( $wpdb->prepare( "SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE %s", $like ) ); foreach ( (array) $names as $name ) { delete_transient( substr( (string) $name, strlen( '_transient_' ) ) ); } } /** * The client, built once per request. */ private static function client(): Cepis\Client { static $client = null; if ( null === $client ) { $client = new Cepis\Client( baseUrl: Cepis_Woo_Options::base_url(), timeout: 5.0, maxAttempts: 2, totalTimeout: 8.0, userAgent: 'cepis-woocommerce/' . CEPIS_WOO_VERSION . ' (+https://cep.is)', transport: new Cepis_Woo_Transport(), ); } return $client; } /** * The API's own 404 body, reproduced so the browser cannot tell the two * modes apart. * * @return array{status:int, body:array, retry_after:?int} */ private static function not_found(): array { return array( 'status' => 404, 'body' => array( 'erro' => 'cep_nao_encontrado', 'mensagem' => 'CEP não existe na base do DNE', ), 'retry_after' => null, ); } }